2012-03-13 11 views
10

Quiero poder dejar de escuchar en un socket de servidor en Linux y asegurarme de que todas las conexiones que están abiertas desde el punto de vista del cliente se manejan correctamente y no abruptamente cerradas (es decir: receive ECONNRESET) .Graceful Shutdown Server Socket en Linux

es decir:

sock = create_socket(); 
listen(sock, non_zero_backlog); 
graceful_close(sock); 

Si el pensamiento de llamar a close() y la manipulación de los zócalos ya accept'd sería suficiente, pero no puede haber conexiones que están abiertos en el retraso del núcleo que se cierra bruscamente si llamas cerca() en el socket del servidor.

+0

Es posible que pueda hacerlo con ['shutdown'] (http://linux.die.net/man/2/shutdown). No lo he probado, así que no sé si funcionará. –

+0

No creo que haya una manera de hacer esto. Eche un vistazo al final de la discusión aquí: http://fixunix.com/networking/535700-disonnecting-tcp-listening-socket.html – Nick

+2

@drscroogemcduck defina lo que quiere decir con "correctamente". Obtener un RST para una conexión TCP semiabierta * es * correcto, por RFC. – tbert

Respuesta

5

La única manera de trabajar para hacer eso (que he encontrado) es:

  1. prevenir accept() de la adición de más clientes

  2. tener una lista de los sockets abiertos en algún lugar y esperar hasta todos ellos están bien cerradas que significa:

    • usando shutdown() para decirle al cliente que ya no trabajar en ese socket

    • llamada read() por un tiempo para asegurarse de que todo el cliente ha enviado en Mientras tanto se ha tirado

    • a continuación, utilizando close() para liberar a cada cliente zócalo.

  3. entonces, usted puede de manera segura close() el socket de escucha.

Puede (y debe) utilizar un tiempo de espera para asegurarse de que las conexiones inactivas no durarán para siempre.

+0

SO_REUSEADDR parece ser una solución decente en sockets locales, es probable que todavía sea lo mejor para salir limpiamente, pero eso posiblemente no sea posible en todas las situaciones. –

2

Estás viendo una limitación de la API de socket TCP. Puede mirar ECONNRESET como la versión de socket de EOF o, puede implementar un protocolo de nivel superior sobre TCP que informa al cliente de una desconexión inminente.

Sin embargo, si intenta la última alternativa, tenga en cuenta la intratable Two Armies Problem que hace imposible el apagado correcto en el caso general; esto es parte de la motivación para el mecanismo de restablecimiento de la conexión TCP tal como está. Incluso si pudiera escribir graceful_close() de una manera que funcionara la mayor parte del tiempo, probablemente todavía tendría que tratar con ECONNRESET a menos que el proceso del servidor pueda esperar para recibir un graceful_close_ack del cliente.

Cuestiones relacionadas