2010-10-09 11 views
7

¿Cuál es la mejor manera de implementar un zócalo sin bloqueo en Java? ¿O hay tal cosa? Tengo un programa que se comunica con un servidor a través del socket, pero no quiero que la llamada del socket bloquee/cause demora si hay un problema con los datos/conexión.zócalo Java sin bloqueo

+0

Hola, creo que su pregunta hace poco, pero creo que es un poco tarde. De todos modos, creo que es una buena pregunta, así que aquí está mi respuesta. – Teocci

Respuesta

0

paquete java.nio ofrece Selector de trabajo muy similar a como en C.

2

Aparte de usar IO no bloqueo, podría encontrar que es mucho más fácil de tener un hilo de escritura para su conexión.

3

Varias de estas respuestas son incorrectas. SocketChannel.configureBlocking(false) lo pone en modo sin bloqueo. No necesitas un Selector para hacer eso. Solo necesita un Selector para implementar tiempos de espera o multiplexado E/S con sockets no bloqueantes.

-1

Acabo de escribir este código. Funciona bien . Este es un ejemplo de Java NIO como se menciona en las respuestas anteriores, pero aquí publico el código.

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

inutilizable. Este código girará en bucle mientras no haya conexiones. Una versión sensata de esto usaría modo de bloqueo o un 'Selector'. – EJP

+0

Creo que esta solución es muy similar al enfoque de bloqueo, la idea de usar un enfoque no bloqueante es crear un controlador para manejar el aceptar cada vez que ocurra ese evento . Cuando usa esto mientras (verdadero) para obtener el socket es como si estuviera bloqueando el hilo hasta que ocurra una conexión con el cliente. – Teocci

2

Java no bloqueando toma, introducido en Java 2 Standard Edition 1.4, permitir la comunicación entre aplicaciones neta sin el bloqueo de los procesos mediante los zócalos. Pero, ¿qué es un socket sin bloqueo, en qué contextos puede ser útil y cómo funciona?

¿Qué es una toma sin bloqueo?

Un zócalo sin bloqueo permite la operación de entrada/salida en un canal sin bloquear los procesos que lo utilizan. Esto significa un "asíncrono de alto rendimiento" operaciones de lectura/escritura (algunas personas no pueden convenidas con él)

Ok, en qué contextos puede ser útil?

Supongamos que desea implementar un servidor que acepte conexiones de clientes diversas. Supongamos, también, que le gustaría que el servidor pueda procesar múltiples solicitudes simultáneamente. Utilizando la forma tradicional, tiene dos opciones para desarrollar dicho servidor:

  • Implemente un servidor multihilo que maneje manualmente un hilo para cada conexión.
  • Uso de un módulo externo de terceros.

Ambas soluciones funcionan, pero si se adopta la primera, debe desarrollar toda la solución de administración de subprocesos, con concurrencia relacionada y problemas de conflicto. La segunda solución hace que la aplicación dependa de un módulo externo que no sea JDK y probablemente deba adaptar la biblioteca a sus necesidades. Mediante el socket sin bloqueo, puede implementar un servidor sin bloqueo sin gestionar directamente los hilos o recurrir a módulos externos.

Cómo funciona?

Por ejemplo, puede utilizar la clase AsynchronousServerSocketChannel, que proporciona un canal asincrónico sin bloqueo para sockets de escucha orientados a la transmisión.

Para usarlo, primero ejecutar su método estático open() y luego bind() a un puerto específico . A continuación, ejecutará su método accept(), transfiriéndole una clase que implementa la interfaz CompletionHandler. Muy a menudo, encontrará ese controlador creado como clase interna anónima.

Desde este objeto AsynchronousServerSocketChannel, invoca accept() para que comience a escuchar conexiones, pasando a una instancia personalizada CompletionHandler. Cuando invocamos accept(), regresa inmediatamente. Tenga en cuenta que esto es diferente del enfoque de bloqueo tradicional; mientras que el método accept()bloqueado hasta que un cliente conectado al mismo, el método AsynchronousServerSocketChannelaccept() lo maneje por usted.

Aquí tienes un ejemplo:

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(); 
     } 
    } 
} 

puede encontrar the full code here