2010-10-09 17 views
7

Qual è il modo migliore per implementare un socket non bloccante in Java? O c'è una cosa del genere? Ho un programma che comunica con un server tramite socket ma non voglio che la chiamata socket blocchi/causi ritardo se c'è un problema con i dati/connessione.Presa Java non bloccante

+0

Ciao, ho trovato la tua domanda da poco ma penso che è un po 'in ritardo. Comunque penso sia una buona domanda, quindi ecco la mia risposta .. – Teocci

risposta

0

pacchetto java.nio fornisce Selettore di lavoro molto simile a come in C.

2

Oltre ad utilizzare non IO blocco, si potrebbe trovare è molto più semplice di avere un filo di scrittura per la connessione.

3

Molte di queste risposte non sono corrette. SocketChannel.configureBlocking(false) lo mette in modalità non bloccante. Non hai bisogno di un selettore per farlo. È necessario solo un selettore per implementare timeout o multiplexed I/O con socket non bloccanti.

-1

Ho appena scritto questo codice. Funziona bene . Questo è un esempio di NIO Java come menzionato nelle risposte precedenti ma qui inserisco il codice.

ServerSocketChannel ssc = null; 
try { 
    ssc = ServerSocketChannel.open(); 
    ssc.socket().bind(new InetSocketAddress(port)); 
    ssc.configureBlocking(false); 
    while (true) { 
     SocketChannel sc = ssc.accept(); 
     if (sc == null) { 
      // No connections came . 
     } else { 
      // You got a connection. Do something 
     } 
    } 
} catch (IOException e) { 
    e.printStackTrace(); 
} 
+2

Inusabile. Questo codice girerà in loop mentre non ci sono connessioni. Una versione sana di questo userebbe la modalità di blocco o un 'Selector'. – EJP

+0

Penso che questa soluzione sia molto simile all'approccio di blocco, l'idea di usare un approccio non bloccante è creare un gestore per gestire l'accettazione ogni volta che si verifica quell'evento . Quando si utilizza questo mentre (true) per ottenere il socket è come si sta bloccando il thread fino a quando si verifica una connessione client. – Teocci

2

Java socket non bloccante, introdotto in Java 2 Standard Edition 1.4, consentire la comunicazione tra le applicazioni netto senza ostruire i processi utilizzando le prese. Ma cos'è un socket non bloccante, in quali contesti può essere utile e come funziona?

Che socket non bloccante è?

Un socket non bloccante consente l'operazione di input/output su un canale senza bloccare i processi che lo utilizzano. Ciò significa che un "asincrona ad alte prestazioni" operazioni lettura/scrittura (alcune persone potrebbero non concordate con quella)

Ok, In quali contesti può essere utile?

Supponiamo che si desideri implementare un server che accetta connessioni client diverse. Supponiamo, inoltre, che il server sia in grado di elaborare più richieste contemporaneamente. Usando il modo tradizionale hai due opzioni per sviluppare un server del genere:

  • Implementare un server multi-thread che gestisce manualmente un thread per ciascuna connessione.
  • Utilizzo di un modulo esterno di terze parti.

Entrambe le soluzioni funzionano, ma adottando la prima è necessario sviluppare l'intera soluzione di gestione dei thread, con relativi problemi di concorrenza e conflitto. La seconda soluzione rende l'applicazione dipendente da un modulo esterno non JDK e probabilmente devi adattare la libreria alle tue necessità. Tramite il socket non bloccante, è possibile implementare un server non bloccante senza gestire direttamente i thread o ricorrere a moduli esterni.

Come funziona?

Ad esempio, è possibile utilizzare la classe AsynchronousServerSocketChannel, che fornisce un canale asincrono non bloccante per socket di ascolto orientati al flusso.

di usarlo, prima di eseguire il metodo statico open() e poi bind() ad una specifica porto. Successivamente, eseguirai il suo metodo accept(), passando ad esso una classe che implementa l'interfaccia CompletionHandler. Molto spesso, troverai questo gestore creato come classe interna anonima .

Da questo oggetto AsynchronousServerSocketChannel, si invoca accept() per indicare che inizia l'ascolto delle connessioni, passando ad esso un'istanza personalizzata CompletionHandler. Quando invochiamo accept(), restituisce immediatamente. Si noti che questo è diverso dal tradizionale approccio di blocco; mentre il metodo bloccato fino a quando un client si è connesso a esso, il metodo AsynchronousServerSocketChannelaccept() lo gestisce per te.

Ecco un esempio:

public class NioSocketServer 
{ 
    public NioSocketServer() 
    { 
     try { 
      // Create an AsynchronousServerSocketChannel that will listen on port 5000 
      final AsynchronousServerSocketChannel listener = AsynchronousServerSocketChannel 
        .open() 
        .bind(new InetSocketAddress(5000)); 

      // Listen for a new request 
      listener.accept(null, new CompletionHandler<AsynchronousSocketChannel, Void>() 
      { 
       @Override 
       public void completed(AsynchronousSocketChannel ch, Void att) 
       { 
        // Accept the next connection 
        listener.accept(null, this); 

        // Greet the client 
        ch.write(ByteBuffer.wrap("Hello, I am Echo Server 2020, let's have an engaging conversation!\n".getBytes())); 

        // Allocate a byte buffer (4K) to read from the client 
        ByteBuffer byteBuffer = ByteBuffer.allocate(4096); 
        try { 
         // Read the first line 
         int bytesRead = ch.read(byteBuffer).get(20, TimeUnit.SECONDS); 

         boolean running = true; 
         while (bytesRead != -1 && running) { 
          System.out.println("bytes read: " + bytesRead); 

          // Make sure that we have data to read 
          if (byteBuffer.position() > 2) { 
           // Make the buffer ready to read 
           byteBuffer.flip(); 

           // Convert the buffer into a line 
           byte[] lineBytes = new byte[bytesRead]; 
           byteBuffer.get(lineBytes, 0, bytesRead); 
           String line = new String(lineBytes); 

           // Debug 
           System.out.println("Message: " + line); 

           // Echo back to the caller 
           ch.write(ByteBuffer.wrap(line.getBytes())); 

           // Make the buffer ready to write 
           byteBuffer.clear(); 

           // Read the next line 
           bytesRead = ch.read(byteBuffer).get(20, TimeUnit.SECONDS); 
          } else { 
           // An empty line signifies the end of the conversation in our protocol 
           running = false; 
          } 
         } 
        } catch (InterruptedException e) { 
         e.printStackTrace(); 
        } catch (ExecutionException e) { 
         e.printStackTrace(); 
        } catch (TimeoutException e) { 
         // The user exceeded the 20 second timeout, so close the connection 
         ch.write(ByteBuffer.wrap("Good Bye\n".getBytes())); 
         System.out.println("Connection timed out, closing connection"); 
        } 

        System.out.println("End of conversation"); 
        try { 
         // Close the connection if we need to 
         if (ch.isOpen()) { 
          ch.close(); 
         } 
        } catch (I/OException e1) 
        { 
         e1.printStackTrace(); 
        } 
       } 

       @Override 
       public void failed(Throwable exc, Void att) 
       { 
        ///... 
       } 
      }); 
     } catch (I/OException e) { 
      e.printStackTrace(); 
     } 
    } 

    public static void main(String[] args) 
    { 
     NioSocketServer server = new NioSocketServer(); 
     try { 
      Thread.sleep(60000); 
     } catch (Exception e) { 
      e.printStackTrace(); 
     } 
    } 
} 

Potete trovare the full code here