2012-01-03 10 views
9

Suponga que un socket TCP en el host local de Linux está en un estado conectado con un host remoto. El host local está utilizando epoll_wait para recibir notificaciones de eventos en el socket con el host remoto.Epoll y apagado unidireccional remoto

Si el host remoto llamara:

shutdown(s,SHUT_WR); 

en su conector conectado para indicar que se realiza la transmisión, lo que evento (s) se epoll_wait retorno en el host local para su zócalo?

Supongo que EPOLLIN siempre se devolverá y una llamada recv posterior devolverá 0 para indicar que el lado remoto ha terminado de transmitir.

¿Qué pasa con EPOLLHUP o EPOLLRDHUP? (¿Y cuál es la diferencia entre estos dos eventos)?

¿O incluso EPOLLERR?

Si el host remoto llama "cerrar" en lugar de "apagar", ¿cambia la respuesta a cualquiera de los anteriores?

Respuesta

18

Estoy respondiendo esto después de hacer el trabajo pesado para encontrar la respuesta.

Un socket que escucha eventos epoll normalmente recibirá un EPOLLRDHUP (además de EPOLLIN) indicador de evento cuando el interlocutor remoto llama al cerrar o cerrar (SHUT_WR). Esto no necesariamente significa que el socket está muerto. Las llamadas posteriores a recv() devolverán los datos no leídos en el socket y eventualmente se devolverá "0" para indicar EOF. Incluso es posible enviar datos de vuelta si el par remoto solo se cerró a la mitad de su socket.

La única excepción notable es si el par remoto está utilizando la opción SO_LINGER habilitada en su socket con un valor de retraso de "0". El resultado de cerrar un socket de este tipo puede hacer que se envíe un TCP RST en lugar de un FIN. Por lo que he leído, un evento de restablecimiento de conexión generará un EPOLLHUP o un EPOLLERR. (No he tenido tiempo de confirmarlo, pero tiene sentido).

Existe cierta documentación que sugiere que hay implementaciones de Linux anteriores que no son compatibles con EPOLLRDHUP, por lo que EPOLLHUP se genera en su lugar.

Y por lo que vale, en mi caso particular, encontré que no es demasiado interesante tener código que casos especiales eventos EPOLLHUP o EPOLLRDHUP. En su lugar, simplemente trate estos eventos de la misma manera que EPOLLIN/EPOLLOUT y llame a recv() (o send() según corresponda). Pero preste mucha atención a los códigos de retorno devueltos por recv() y send().

+1

Tenía más preguntas sobre el comportamiento aquí, así que hice una inmersión detallada en estas interacciones: https://medium.com/where-the-flamingcow-roams/down-the-epoll-rabbit-hole-5c0447cb6329 – flamingcow