2010-06-29 21 views
7

Tenemos una arquitectura de servidor de cliente simple entre nuestro dispositivo móvil y nuestro servidor ambos escritos en Java. Una implementación de ServerSocket y Socket extremadamente simple. Sin embargo, un problema es que cuando el cliente finaliza abruptamente (sin cerrar correctamente el socket), el servidor no sabe que está desconectado. Además, el servidor puede continuar escribiendo en este socket sin obtener ninguna excepción. ¿Por qué?¿El socket Java no arroja excepciones en un socket muerto?

Según la documentación, los sockets de Java deben arrojar excepciones si intenta escribir en un socket que no es accesible en el otro extremo.

Respuesta

0

Las comunicaciones TCP/IP pueden ser muy extrañas. TCP volverá a intentar durante un buen rato en las capas inferiores de la pila sin dejar que las capas superiores sepan que ocurrió algo.

Espero que después de un período de tiempo (de 30 segundos a unos minutos) vea un error, pero no lo he probado. Estoy empezando a ver cómo funcionan las aplicaciones TCP.

Es posible que pueda ajustar las especificaciones de TCP (reintento, tiempo de espera, etc.) pero, una vez más, no lo he molestado demasiado.

Además, puede ser que esté totalmente equivocado y la implementación de Java que está utilizando es escasa.

2

La conexión con el tiempo de espera de retransmisión (RTO) eventualmente terminará. Sin embargo, el RTO se calcula utilizando un algoritmo complejo basado en la latencia de red (RTT), véase este RFC,

http://www.ietf.org/rfc/rfc2988.txt

lo tanto en una red móvil, esto puede ser de minutos. Espere 10 minutos para ver si puede obtener un tiempo de espera.

La solución a este tipo de problema es agregar un latido del corazón en su propio protocolo de aplicación y cortar la conexión cuando no recibe ACK para el latido del corazón.

1

La palabra clave aquí (without closing the socket properly).

sockets siempre se deben adquirir y eliminar de esta manera:

final Socket socket = ...; // connect code 

try 
{ 
    use(socket); // use socket 
} 
finally 
{ 
    socket.close(); // dispose 
} 

Incluso con esta precauciones que debe especificar tiempos de aplicación, específicos de su protocolo.

Mi experiencia ha demostrado que, desafortunadamente, no puede usar ninguna de las funciones de tiempo de espera de manera confiable (por ejemplo, no hay tiempo de espera para las operaciones de escritura e incluso las operaciones de lectura pueden colgarse para siempre).

Es por eso que necesita un hilo de vigilancia que hace cumplir los tiempos de espera de la aplicación y dispone de enchufes que no han respondido por un tiempo.

Una manera conveniente de hacerlo es inicializando Socket y ServerSocket a través de los canales correspondientes en java.nio. La principal ventaja de estos zócalos es que son interruptores interrumpibles, de esa manera puede simplemente interrumpir el hilo que hace el protocolo de zócalo y asegurarse de que el zócalo se deseche correctamente.

Tenga en cuenta que debe exigir el tiempo de espera de las aplicaciones en ambos lados, ya que es solo una cuestión de tiempo y mala suerte cuando puede experimentar sockets que no responden.

0

Para responder a la primera parte de la pregunta (sobre no saber que el cliente se ha desconectado abruptamente), en TCP, no puede saber si una conexión ha finalizado hasta que intente usarla.

La noción de guaranteed delivery in TCP es bastante sutil: la entrega no está realmente garantizada para la aplicación en el otro extremo (depende en realidad de lo que realmente garantizado). Section 2.6 of RFC 793 (TCP) brinda más detalles sobre este tema. This thread on the Restlet-discuss list y this thread on the Linux kernel list también pueden ser de su interés.

Para la segunda parte (no detecta cuando escribe en este conector), esta es probablemente una cuestión de búfer y tiempo de espera (como otros ya han sugerido).

+0

Ya traté de usarlo escribiendo en el socket e incluso entonces no sé si el cliente se ha desconectado. – erotsppa

0

Estoy enfrentando el mismo problema. Creo que cuando registra el socket con un selector, no lanza ninguna excepción. ¿Está utilizando un selector con su zócalo?

Cuestiones relacionadas