2012-09-04 6 views
7

Estoy probando una comunicación cliente-servidor a través de un socket TCP. Escribí el servidor en C y lo estoy ejecutando en una máquina Linux y estoy usando nc como cliente para la prueba.Tubo roto solo en el segundo envío en un socket cerrado

El servidor, después de un intercambio inicial de mensajes con el cliente, envía algunos mensajes periódicamente al cliente sin obtener ninguna respuesta.

Si mato al cliente, espero que la primera send() realizado por el servidor falla con EPIPE de error, pero esto se vuelve a cabo sólo en la segunda send() después de que el cliente ha ido! El primer send() después de matar al cliente puede enviar correctamente 1100 bytes al socket (supongo que cerrado). La siguiente operación send() finaliza con EPIPE como se exepción.

¿Hay alguien que pueda explicarme este comportamiento? ¿Es por el hecho de que escribo en la pila de TCP/IP por lo que depende de la pila entregar cuando puede? En caso afirmativo, ¿cómo puedo verificar el estado de la conexión? Para estar seguro de que el par todavía está allí.

Respuesta

4

La conexión TCP normal es un saludo de cuatro vías.

http://en.wikipedia.org/wiki/Transmission_Control_Protocol

Cuando se está matando el cliente del segmento FIN se envía desde el lado del cliente al servidor y la pila de protocolos de servidor envía el ACK .

Aquí, si el servidor intentó leer datos, la llamada de lectura devolvería un valor de 0, por lo que su programa de servidor puede entender que el par se ha cerrado y normalmente cerraría el socket de conexión después de esto. Esto permitiría enviar FIN desde el lado del servidor y se completará el protocolo de enlace de 4 vías normal después de la recepción del último ACK desde el lado del cliente.

(Pl leer Q 2.1 de http://www.faqs.org/faqs/unix-faq/socket/)

Pero aquí se están escribiendo datos en el servidor, por lo que el servidor es conseguir un REINICIAR desde el cliente sólo después de enviar los datos. Entonces está recibiendo el error después de la primera operación de envío que está en el segundo envío.

Así que, pl. intente cerrar la conexión desde el lado del cliente abruptamente en lugar de 4 way handsake, estableciendo la opción de demora y tiempo de espera en 0, para que pueda obtener un error (puede ser diferente de EPIPE) en la primera llamada de envío en el lado del servidor. (esto no es una práctica recommnended pero sólo por su comprensión en este caso particular)

Try the following option of nc, nc -L 0 to set the linger option and timeout to 0 

(no he probado esta opción de Carolina del Norte, pl. comprobar si hay detalles en este enlace http://docs.oracle.com/cd/E23824_01/html/821-1461/nc-1.html)

Ejemplo de nc desde el sitio anterior,

Connect to TCP port, send some data and terminate the connection with 
TCP RST segment 
(instead of classic TCP closing handshake) by setting the linger option and 
timeout to 0: 

$ echo "foo" | nc -L 0 host.example.com 22 
+0

Gracias por su respuesta, detallada y clara. Desafortunadamente no puedo probar la opción nc que me sugirió porque el comando en mi máquina Linux no parece ser compatible.Por cierto, la documentación que me indicaste y las explicaciones que me diste son claras y útiles. ¡Gracias! – Igor

Cuestiones relacionadas