I want to be able to stop listening on a server socket in linux and ensure that all connections that are open from a client's point of view are correctly handled and not abruptly closed (ie: receive ECONNRESET).
ie:
sock = create_socket();
listen(sock, non_zero_backlog);
graceful_close(sock);
if thought calling close() and handling already accept'd sockets would be enough but there can be connections that are open in the kernel backlog which will be abruptly closed if you call close() on the server socket.
The only working way to do that (that I have found) is to:
prevent accept()
from adding more clients
have a list of the open sockets somewhere and to wait until they are all properly closed which means:
using shutdown()
to tell the client that you will no longer work on that socket
call read()
for a while to make sure that all the client has sent in
the meantime has been pulled
then using close()
to free each client socket.
THEN, you can safely close()
the listening socket.
You can (and should) use a timeout to make sure that idle connections will not last forever.
You are looking at a limitation of the TCP socket API. You can look at ECONNRESET
as the socket version of EOF
or, you can implement a higher level protocol over TCP which informs the client of an impending disconnection.
However, if you attempt the latter alternative, be aware of the intractable Two Armies Problem which makes graceful shutdown impossible in the general case; this is part of the motivation for the TCP connection reset mechanism as it stands. Even if you could write graceful_close()
in a way that worked most of the time, you'd probably still have to deal with ECONNRESET
unless the server process can wait forever to receive a graceful_close_ack
from the client.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With