2011-05-20 6 views
5

Tengo un problema con los zócalos TCP/IP de Java: mi aplicación Java continuará interminablemente para enviar datos a un servidor, incluso si el servidor se apaga (sin una desconexión apropiada de TCP/IP) mientras tanto.¿Cómo informan los zócalos Java TCP/IP sobre el éxito o el fracaso de la transmisión en la aplicación?

estoy usando el siguiente código para enviar los datos:

PrintWriter out = PrintWriter(socket.getOutputStream(), true); 
out.write("text"); 

if (out.checkError()) { 
    System.err.println("Error sending string!"); 
} 

En another Stack Overflow question, me encontré con la siguiente respuesta:

TCP/IP (y por lo tanto tomas java) garantizará que usted envía con éxito los datos O recibe un error (excepción en el caso de Java) eventualmente.

¿Mi código es suficiente para informarme de que la pila TCP/IP no puede enviar correctamente mi cadena o debo hacer algo adicionalmente?

Por cierto: ¿fue correcto abrir una nueva pregunta a pesar de que la otra pregunta era similar? No contestó mi pregunta de manera satisfactoria y solo pude agregar una nueva respuesta, no un nuevo comentario.

+0

Lo primero que me gustó de ti es ... tu nombre TAJMAHAL :). En segundo lugar, puede hacer tantas preguntas como desee, ya que es gratuita y abierta. _Pero no debería. Si encuentra una pregunta similar, intente encontrar una solución para su versión. Si de todos modos no es posible, hazlo como lo hiciste. Refiere a otra pregunta lo que ya viste, pon aquí lo que probaste y el lugar donde piensas que estás atrapado. Los chicos de Stackoverflow son geniales si tienes una pregunta genuina/buena. De lo contrario, su pregunta puede ser cerrada/movida/downvoted, etc. Sufriste todo eso :-) – Mayank

Respuesta

1

Lo que no mencioné (ya que pensé que no era relevante en ese momento) es que estoy tratando de hacer esto en Android.

Después de varias semanas de pruebas, parece que la implementación de Android de las clases de redes Java estándar se comporta de manera muy diferente a Oracle JRE. En Android, aparentemente es imposible detectar de manera confiable si la conexión se ha cerrado, incluso si la cerré yo mismo. [Stream].write() intentará escribir durante varios minutos. Por lo tanto, en Android, parece que siempre tendrá que enviar sus propios keep-alive (¡y verificar la recepción!) Para detectar una conexión interrumpida.

Las otras respuestas a esta pregunta funcionarán bien con Oracle JRE. ¡Gracias de nuevo!

Si alguien puede proporcionar más información sobre este tema, hágalo.

+0

Estoy de acuerdo, los enchufes en Android tienen errores, a menudo no generan ninguna excepción cuando deberían. –

0

A veces, aunque el servidor ha fallado, su aplicación cliente no está informada al respecto. Por lo general, este es un enrutador defectuoso que, en algún lugar, no cierra ambos lados de la conexión. Debe configurar keep-alives para que pueda detectar este tipo de falla.

Dependiendo de su sistema operativo, hay formas de cambiar el intervalo de prueba de mantener vivo.

4

Puede que tenga dos problemas: PrintWriter es una extraña bestia en el mundo Java Stream/Reader/Writer en que se traga excepciones y requiere que comprobar explícitamente si hay errores.

El único uso para esto (en mi opinión) son las transmisiones estándar (System.out y System.err), donde el error al escribir la salida no debe detener la aplicación (por ejemplo, si no hay salida estándar disponible).

Reemplázalo con un OutputStreamWriter y serás informado sobre los errores tan pronto como Java los conozca.

Eso me lleva al segundo problema posible: TCP/IP no tiene ningún paquete automático para mantener vivo: así que si su conexión se corta de alguna manera, en realidad no lo notará hasta que intente enviar datos.

Así que si se conecta a alguna toma, enviar algunos paquetes, esperar un poco y luego pierda la conexión, sólo se le notificará del hecho cuando vuelva a intentar enviar algunos datos. Esto es inherente al protocolo TCP/IP y no a la culpa de Java.

Si desea reducir el problema, puede enviar mensajes periódicos keep-alive/ping sin efecto real, excepto que comprueban si la conexión aún está activa.

+0

Pero si desconecto el cable de red del servidor y sigo enviando un mensaje cada segundo, ¿cuánto tiempo debería tomar 'out.checkError() 'para descubrir que la transmisión no tuvo éxito? ¿Segundos? ¿Minutos? Horas? – tajmahal

+0

Reemplacé el PrintWriter con un OutputStreamWriter pero aún puedo desconectar el cable de red y transmitir por años sin obtener una excepción. – tajmahal

1

Su pregunta es lo suficientemente diferente como para decir. Sin embargo, Google tiene mucho que decir sobre este tipo de cosas. Los keep-alives (SO_KEEPALIVE) no están diseñados para este tipo de cosas.De lo que he leído la especificación TCP dice que deben no ser enviado más de una vez cada dos horas y que depende de su sistema operativo para su gestión por lo que no tienen mucho control. Destaco de lo que he leído.

Si usted los puede usar más de una vez cada dos horas, no importa en su caso, sin embargo, ya que está enviando datos continuamente. Keep-Alives solo es necesario si desea detectar una conexión interrumpida mientras no está enviando datos.

Si estuviera usando el OutputStream del Socket directamente, arrojaría una excepción cuando intente enviarlo a un destino no disponible (por cualquier razón que sea). Dado que está utilizando PrintWriter, es necesario comprobar si hay errores de forma manual utilizando checkError().

Por lo tanto, en resumen: Sí, es suficiente para su propósito.

+0

Entonces, ¿por qué no funciona para mí? Puedo desenchufar el cable del servidor y seguir enviándole datos por _minutos_ sin obtener un error. Actualmente estoy enviando un mensaje cada segundo. ¿No debería la pila TCP/IP notar las ACKS faltantes y notificar a la capa de aplicación? – tajmahal

+0

Sí, debería. Intente usar 'OutputStream' directamente y vea si eso mejora las cosas para usted:' socket.getOutputStream(). Write ("text" .toBytes()); '. Debería arrojar una excepción. O use la clase sugerida por Joachim. Si hubiera visto su respuesta, probablemente no me habría molestado en escribir la mía. –

0

Se aplica una condición especial cuando se cierra el zócalo. Dependiendo del socket SO_LINGER (ver article) que establezca, la llamada close() retornará inmediatamente o esperará hasta que todas las transmisiones TCP pendientes hayan sido exitosas o se haya producido un error, que luego será señalado por una IOException lanzada desde la implementación close().

También SO_TIMEOUT tiene un efecto sobre cuándo se agotarán los reintentos.

Cuestiones relacionadas