linux - tag - ¿Qué pasó con el socket si la red se ha roto?
puddletag (2)
Sé que si el programa en A muere (como el volcado del núcleo), eso provocará que un paquete RST pase a B. Por lo tanto, cualquier intento de lectura de B conducirá a un EOF, y cualquier intento de escritura de B conducirá a SIGPIPE. ¿Estoy en lo cierto?
Parcialmente. RST causa un ECONNRESET, no un EOF, al leer, y EPIPE al escribir.
Si, sin embargo, supongamos que la red se ha roto (como la falla del cable / enrutador) en A, ¿qué ocurre con el intento de lectura / escritura de B? En mi situación, todos los enchufes se han configurado como no bloqueantes. Como resultado, ¿me es imposible detectar un error de red?
Imposible leer solo, a menos que use un tiempo de espera de lectura, por ejemplo, a través de select (), y tome un tiempo de espera como una falla, que podría no serlo. Al escribir, eventualmente obtendrá un EPIPE, pero podría tomar algún tiempo y varios intentos debido al almacenamiento en búfer y los reintentos.
Supongamos un modelo de red simple: A ha creado con éxito una conexión TCP a B, y se están comunicando entre sí de esta manera.
A <----------> B
Sé que si el programa en A muere (como el volcado del núcleo), eso provocará que un paquete RST pase a B. Por lo tanto, cualquier intento de lectura de B conducirá a un EOF, y cualquier intento de escritura de B conducirá a SIGPIPE. ¿Estoy en lo cierto?
Si, sin embargo, supongamos que la red se ha roto (como la falla del cable / enrutador) en A, ¿qué ocurre con el intento de lectura / escritura de B? En mi situación, todos los enchufes se han configurado como no bloqueantes. Como resultado, ¿me es imposible detectar un error de red?
Por cierto, noté que hay una opción SO_KEEPALIVE
en el socket que puede ser útil para mí http://tldp.org/HOWTO/html_single/TCP-Keepalive-HOWTO/ . Pero me pregunto cuánto costará si configuro el intervalo de exploración en 2 ~ 3 segundos (que de manera predeterminada es de 75 segundos). Y parece que la configuración de intervalos es global, ¿afectará esto a todos los enchufes de la máquina?
Pregunta final ... Digamos que la red se ha roto y cualquier intento de escritura causaría EPIPE algún tiempo después. Sin embargo, si, en lugar de tratar de escribir, pongo este conector en un dispositivo epoll, ¿qué sucederá entonces? ¿Epoll_wait devolverá el evento EPOLLHUP o EPOLLERR?
Hay muchas otras formas en que una conexión TCP puede pasar desapercibida
- alguien tira de un cable de red entre ellos.
- la computadora en el otro extremo se numera.
- una puerta de enlace nat entre medias silenciosamente cae la conexión
- el sistema operativo en el otro extremo se cuelga con fuerza.
- los paquetes FIN se pierden.
- Errores indetectables: un enrutador entre los puntos finales puede arrojar paquetes. (incluidos los paquetes de control) reff
En todos los casos, puede saberlo cuando intente escribir en el zócalo por este motivo mediante un error SIGPIPE en su programa y rescindirlo.
Por lectura () no se puede saber si el otro lado vive o no. Gracias Por qué SO_KEEPALIVE útil. Keepalive no es invasivo, y en la mayoría de los casos, si tiene dudas, puede activarlo sin el riesgo de hacer algo mal. Pero recuerde que genera tráfico de red adicional, que puede tener un impacto en los enrutadores y firewalls.
¡Y esto también afecta a todos los enchufes de tu máquina! (Estás en lo cierto). Y porque SO_KEEPALIVE aumenta el tráfico y consume CPU. Lo mejor es configurar el manejador SIGPIPE, si hay alguna posibilidad de que la aplicación escriba alguna vez en una conexión interrumpida.
También use SO_KEEPALIVE en un lugar razonable en la aplicación. Es malo usarlo durante toda la duración de la conexión (es decir, utilice so_keepalive cuando el servidor funcione durante mucho tiempo en la consulta del cliente).
Establezca el intervalo de exploración Dependencias en su aplicación o diga Protocolo de capa de aplicación.
Si bien habilita TCP keepalive, lo detectará eventualmente, al menos durante un par de horas.
Diga si la red se ha roto y, sin embargo, en lugar de tratar de escribir, el socket se inserta en algún dispositivo epoll:
El segundo argumento en epoll:
n = epoll_wait (efd, events, MAXEVENTS, -1);
Establecer con el código correcto relacionado con el evento, la buena práctica es verificar este código para
precaución como sigue.
n = epoll_wait (efd, events, MAXEVENTS, -1);
for (i = 0; i < n; i++)
{
if ((events[i].events & EPOLLERR) ||
(events[i].events & EPOLLHUP) ||
(!(events[i].events & EPOLLIN)))
{
/* An error has occured on this fd, or the socket is not
ready for reading (why were we notified then?) */
fprintf (stderr, "epoll error/n");
close (events[i].data.fd);
continue;
}
else if (sfd == events[i].data.fd)
{
/* We have a notification on the listening socket, which
means one or more incoming connections. */
// Do what you wants
}
}
Donde significa EPOLLRDHUP es:
Transmita la conexión cerrada del mismo par o cierre la mitad de la conexión. (Este indicador es especialmente útil para escribir código simple para detectar el apagado por pares cuando se utiliza la supervisión de activación por flanco).