30
votes

Is it wise/safe to close() a socket directly after the last send()?

I know that TCP is supposed to try to deliver all remaining data in the send buffer even after closing the socket, but can I really count on that?

I'm making sure that there is no remaining data in my receive buffer so that no RST will be sent following my close.


In my case, the close is actually the very last statement of code before calling exit().

Will the TCP stack really continue to try and transmit the data even after the process sending it has terminated? Is that as reliable as waiting for an arbitrary timeout myself before calling close() by setting SO_LINGER?

That is, do the same TCP timeouts apply, or are they shorter? With a big send buffer and a slow connection, the time to actually transfer all the buffered data could be substantial, after all.


I'm not interested at all in being notified of the last byte sent; I just want them to eventually arrive at the remote host as reliably as possible.

Application layer acknowledgements are not an option (the protocol is HTTP, and I'm writing a small server).

1
It depends upon the implementation, but in general, yes, a close() will flush any data remaining in the buffer before it actually tears down the socket. Mileage may vary if you terminate the entire process in addition to calling close().aroth
@aroth Mileage will not vary if you exit the process. There is no difference between the two cases. If you want to maintain the contrary please provide an authoritative reference.user207421
@EJP - An authoritative reference on what might happen in arbitrary programs? I don't think such a thing exists. But it's simple enough to posit a plausible example. Say you've got a program that delegates all network operations to a separate thread, like most programs should. It's possible for the main thread to terminate the process (gracefully or otherwise) while the background thread is calling close(). Will the call succeed in that case? I doubt it. Granted, what you say should hold true for any single-threaded program. But not all programs are single-threaded.aroth
@aroth No, an authoritative reference that says what you said about 'mileage may vary'. You won't find one. A socket close is a socket close whether it's done by the application or by the kernel when the application exits. Again if you have a counterexample please provide it.user207421

1 Answers

30
votes

I've been reading the The ultimate SO_LINGER page, or: why is my tcp not reliable blog post a lot. I recommend you read it too. It discusses edge cases of large data transfers with regards to TCP sockets.

I'm not the expert at SO_LINGER, but on my server code (still in active development) I do the following:

  1. After the last byte is sent via send(), I call shutdown(sock, SHUT_WR) to trigger a FIN to be sent.

  2. Then wait for a subsequent recv() call on that socket to return 0 (or recv returns -1 and errno is anything other that EAGAIN/EWOULDBLOCK).

  3. Then the server does a close() on the socket.

The assumption is that the client will close his socket first after it has received all the bytes of the response.

But I do have a timeout enforced between the final send() and when recv() indicates EOF. If the client never closes his end of the connection, the server will give up waiting and close the connection anyway. I'm at 45-90 seconds for this timeout.

All of my sockets are non-blocking and I use poll/epoll to be notified of connection events as a hint to see if it's time to try calling recv() or send() again.