2012-05-13 19 views
9

Actualmente estoy escribiendo un código de red ingenuo para un proyecto y un compañero me insinuó la posibilidad de que cuando envío un paquete de información desde el servidor a todos los clientes de forma iterativa podría sufrir un retraso intenso cuando uno de los los clientes no responden adecuadamente¿Hay un OutputStream en el bloqueo de Java? (Sockets)

Lo reconocen por trolling, así que era un tanto escéptico al implementar un hilo secundario que ahora es responsable de enviar datos a un cliente, con una cola que el Servidor simplemente agrega los paquetes que luego lee el hilo para enviar datos

La pregunta que ahora tengo después de pensarlo es si el OutputStream de Java Socket en realidad pone en cola las cosas que quiere enviar por sí mismo, eliminando así la necesidad de una cola de antemano. La posibilidad de tener problemas intensos solo se produce cuando el Servidor está bloqueando, siempre y cuando no reciba una respuesta de un cliente de que se recibió el objeto enviado.

Gracias.

+0

Me he encontrado con un problema similar si trato de obtener la salida o la secuencia de entrada en la función de ejecución de un subproceso.El problema con el bloqueo (para getInputStream y getOutputStream) del socket es porque está en la función de ejecución ... la solución parece ser ponerlo en el constructor, guardar la variable y luego hacer referencia a la variable en ejecución. – Zimm3r

Respuesta

4

Por supuesto, cuando escribe en un socket, esta escritura se almacena en el búfer. El objeto Socket tiene un método setSendBufferSize() para configurar este tamaño de búfer. Si su escritura puede ser almacenada en caché en este búfer, entonces, por supuesto, puede iterar inmediatamente en el siguiente zócalo. De lo contrario, este buffer debe ser enviado inmediatamente al cliente. Por lo tanto, durante el lavado, te bloquearán. Si desea evitar el bloqueo mientras descarga el búfer, debe usar un SocketChannel en E/S sin bloqueo. De todos modos, la mejor opción para escribir simultáneamente en muchos sockets es administrar cada socket con un hilo diferente, para que todas las escrituras se puedan ejecutar al mismo tiempo.

+5

"De lo contrario, este buffer debe ser eliminado inmediatamente del cliente" no es una forma correcta de expresarlo. El búfer se escribe en la red todo el tiempo, de forma asíncrona, pero no se puede enviar hasta que haya espacio en el búfer de recepción del par. Si el par no está leyendo, o está disminuyendo la lectura, su búfer de recepción se llenará, por lo que su búfer de envío se llenará, por lo que sus escrituras posteriores se bloquearán. – EJP

+0

Aunque la publicación de Tomasz fue un mejor ejemplo, esto es exactamente lo que estaba buscando en términos de explicación EJP. Muchas gracias. – salbeira

8

Su amigo tiene razón, pero tiene más que ver con cómo funciona el protocolo . Se deben confirmar los paquetes en gran medida simplificados enviados al cliente. Si el cliente no responde (no lee datos entrantes, la computadora está bajo mucha carga, etc.) el servidor no recibirá acuses de recibo y dejará de enviar los datos. Este mecanismo integrado en TCP/IP evita que un extremo de la comunicación envíe grandes cantidades de datos sin asegurarse de que el otro extremo los haya recibido. Por turnos esto evita el requisito de reenviar grandes cantidades de datos.

En Java esto se manifiesta como bloqueo de escritura en OutputStream. La pila TCP/IP subyacente/sistema operativo no permite el envío de más datos hasta que el cliente esté listo para recibirlo.

¡Usted puede probar esto fácilmente! He implementado servidor simple que acepta la conexión, pero no puede leer los datos de entrada:

new Thread(new Runnable() { 
    @Override 
    public void run() { 
     try { 
      final ServerSocket serverSocket = new ServerSocket(4444); 
      final Socket clientSocket = serverSocket.accept(); 
      final InputStream inputStream = clientSocket.getInputStream(); 
     } catch (IOException e) { 
      e.printStackTrace(); 
     } 

    } 
}).start(); 

y un cliente simple que simplemente envía tantos datos como puede en 4K lotes:

final Socket client = new Socket("localhost", 4444); 
final OutputStream outputStream = client.getOutputStream(); 
int packet = 0; 
while(true) { 
    System.out.println(++packet); 
    outputStream.write(new byte[1024 * 4]); 
} 

El bucle de cliente se cuelga en mi computadora después de 95 iteraciones (su millaje puede variar). Sin embargo, si leo desde inputStream en el hilo del servidor, el ciclo sigue y sigue.

+0

Me he encontrado con un problema similar si trato de obtener la salida o la secuencia de entrada en la función de ejecución de un subproceso. El problema con el bloqueo (para getInputStream y getOutputStream) del socket es porque está en la función de ejecución ... la solución parece ser ponerlo en el constructor, guardar la variable y luego hacer referencia a la variable en ejecución. – Zimm3r

0

Un OutputStream está bloqueando. Probablemente tenga algo de almacenamiento en búfer, pero eso no ayuda mucho si el servidor nunca consume bytes (cualquier búfer fijo eventualmente se llenará). Entonces, tu amigo tiene razón, necesitas escribir un hilo separado, o usar algo más avanzado, como nio.

En el lado de lectura, puede usar available() para evitar el bloqueo. No existe una llamada coincidente en el lado de escritura. Ojalá hubiera.

Cuestiones relacionadas