Cómo detectar una desconexión de socket TCP (con conector C Berkeley)

Estoy usando un bucle para leer un mensaje desde una toma de CA de Berkeley, pero no puedo detectar cuando la toma está desconectada, así que aceptaría una nueva conexión. por favor ayuda

while(true) { bzero(buffer,256); n = read(newsockfd,buffer,255); printf("%s\n",buffer); } 

La única forma en que puede detectar que un socket está conectado es escribiéndole.

Obtener un error en read()/recv() indicará que la conexión está rota, pero que no se produce un error al leer no significa que la conexión esté activa.

Le puede interesar leer esto: http://lkml.indiana.edu/hypermail/linux/kernel/0106.1/1154.html

Además, el uso de TCP Keep Alive puede ayudar a distinguir entre conexiones inactivas y rotas (enviando algo a intervalos regulares incluso si la aplicación no envía datos).

(EDITAR: eliminó la oración incorrecta como lo señaló @Damon, gracias).

Tu problema es que estás ignorando por completo el resultado devuelto por read() . Su código después de read() debería verse al menos así:

 if (n == 0) // peer disconnected break; else if (n == -1) // error { perror("read"); break; } else // received 'n' bytes { printf("%.*s", n, buffer); } 

Y aceptar una nueva conexión debe hacerse en una secuencia separada, no depende del final de la transmisión en esta conexión.

La llamada bzero() tiene sentido, solo una solución para errores previos.

Eso es porque no usaste el tiempo de espera de keepalive. En el lado de recepción, la opción de socket keepalive es la mejor solución para detectar conexiones inactivas.

Pero, en caso de que su aplicación continúe escribiendo en el socket, hay algo para pensar más. Aunque ya ha configurado la opción keepalive en el socket de su aplicación, no puede detectar a tiempo el estado de conexión inactiva del socket, en caso de que su aplicación siga escribiendo en el socket. Eso es debido a la retransmisión de tcp por la stack kernel tcp. tcp_retries1 y tcp_retries2 son parámetros del núcleo para configurar el tiempo de espera de la retransmisión de tcp. Es difícil predecir el tiempo preciso de tiempo de espera de retransmisión porque se calcula mediante el mecanismo RTT. Puedes ver este cálculo en rfc793. (3.7. Comunicación de datos)

https://www.rfc-editor.org/rfc/rfc793.txt

Cada plataforma tiene configuraciones de kernel para la retransmisión de tcp.

 Linux : tcp_retries1, tcp_retries2 : (exist in /proc/sys/net/ipv4) 

http://linux.die.net/man/7/tcp

 HPUX : tcp_ip_notify_interval, tcp_ip_abort_interval 

http://www.hpuxtips.es/?q=node/53

 AIX : rto_low, rto_high, rto_length, rto_limit 

http://www-903.ibm.com/kr/event/download/200804_324_swma/socket.pdf

Debería establecer un valor más bajo para tcp_retries2 (predeterminado 15) si desea detectar temprano la conexión inactiva, pero no es el momento preciso como ya he dicho. Además, actualmente no puede establecer esos valores solo para un solo socket. Esos son los parámetros globales del kernel. Hubo alguna versión de prueba para aplicar la opción de socket de retransmisión de tcp para socket único ( http://patchwork.ozlabs.org/patch/55236/ ), pero no creo que se haya aplicado a la línea principal del kernel. No puedo encontrar la definición de opciones en los archivos de encabezado del sistema.

Como referencia, puede monitorear su opción de socket keepalive a través de ‘netstat –timers’ como a continuación. https://stackoverflow.com/questions/34914278

 netstat -c --timer | grep "192.0.0.1:43245 192.0.68.1:49742" tcp 0 0 192.0.0.1:43245 192.0.68.1:49742 ESTABLISHED keepalive (1.92/0/0) tcp 0 0 192.0.0.1:43245 192.0.68.1:49742 ESTABLISHED keepalive (0.71/0/0) tcp 0 0 192.0.0.1:43245 192.0.68.1:49742 ESTABLISHED keepalive (9.46/0/1) tcp 0 0 192.0.0.1:43245 192.0.68.1:49742 ESTABLISHED keepalive (8.30/0/1) tcp 0 0 192.0.0.1:43245 192.0.68.1:49742 ESTABLISHED keepalive (7.14/0/1) tcp 0 0 192.0.0.1:43245 192.0.68.1:49742 ESTABLISHED keepalive (5.98/0/1) tcp 0 0 192.0.0.1:43245 192.0.68.1:49742 ESTABLISHED keepalive (4.82/0/1) 

Además, cuando ocurre el timeout de keepalive, puede cumplir con diferentes eventos de devolución según las plataformas que use, por lo que no debe decidir el estado de conexión inactiva solo por eventos de devolución. Por ejemplo, HP devuelve el evento POLLERR y AIX devuelve solo el evento POLLIN cuando se produce el tiempo de espera de keepalive. Encontrará el error ETIMEDOUT en la llamada a recv () en ese momento.

En la versión de kernel reciente (desde 2.6.37), puede usar la opción TCP_USER_TIMEOUT que funcionará bien. Esta opción se puede usar para un solo socket.