Escrituras de stream de socket / salida java: ¿bloquean?

Si solo estoy ESCRIBIENDO a un socket en una secuencia de salida, ¿alguna vez se bloqueará? Solo las lecturas pueden bloquear, ¿verdad? Alguien me dijo que las escrituras pueden bloquear pero solo veo una función de tiempo de espera para el método de lectura de un socket: Socket.setSoTimeout() .

No tiene sentido para mí que una escritura pueda bloquear.

Una escritura en un zócalo también puede bloquear, especialmente si es un zócalo TCP. El sistema operativo solo almacenará una cierta cantidad de datos no transmitidos (o transmitidos, pero no reconocidos). Si escribe cosas más rápido de lo que la aplicación remota puede leerlo, el socket eventualmente hará una copia de seguridad y sus llamadas de write se bloquearán.

Respondiendo a estas preguntas de seguimiento:

Entonces, ¿hay un mecanismo para establecer un tiempo de espera para esto? No estoy seguro de qué comportamiento tendría … ¿tal vez tirar datos si los almacenamientos intermedios están llenos? ¿O posiblemente elimines los datos más antiguos en el búfer?

No hay ningún mecanismo para establecer un tiempo de espera de escritura en un java.net.Socket. Hay un método Socket.setSoTimeout() , pero afecta las llamadas accept() y read() … y no write() . Aparentemente, puedes obtener tiempos de espera de escritura si usas NIO, modo sin locking y Selector, pero esto no es tan útil como podrías imaginar.

Una stack TCP implementada correctamente no descarta datos almacenados a menos que la conexión esté cerrada. Sin embargo, cuando obtiene un tiempo de espera de escritura, no está claro si los datos que se encuentran actualmente en los búferes de nivel de sistema operativo han sido recibidos por el otro extremo … o no. El otro problema es que no sabe qué cantidad de datos de su última write se transfirió realmente a los búferes de stack TCP de nivel de sistema operativo. A falta de algún protocolo de nivel de aplicación para resincronizar la transmisión * , lo único seguro después de un tiempo de espera de write es cerrar la conexión.

Por el contrario, si utiliza un socket UDP, las llamadas a write() no se bloquearán durante un período de tiempo significativo. Pero la desventaja es que si hay problemas de red o la aplicación remota no se mantiene, los mensajes se dejarán caer sin notificación a ninguno de los extremos. Además, puede encontrar que los mensajes a veces se entregan a la aplicación remota fuera de servicio. Dependerá de usted (el desarrollador) lidiar con estos problemas.

* En teoría, es posible hacer esto, pero para la mayoría de las aplicaciones no tiene sentido implementar un mecanismo de resincronización adicional sobre una transmisión TCP / IP ya confiable (hasta cierto punto). Y si tuviera sentido, también necesitaría tratar con la posibilidad de que la conexión se cerrara … por lo que sería más simple asumir que se cerró.

La única forma de hacerlo es usar NIO y selectores.

Consulte la descripción del ingeniero de Sun / Oracle en este informe de errores: http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4031100