views:

281

answers:

3

I'm trying to test for a closed socket that has been gracefully closed by the peer without incurring the latency hit of a double send to induce a SIGPIPE.

One of the assumptions here is that the socket if closed was gracefully closed by the peer immediately after it's last write / send. Actual errors like a premature close are dealt with else where in the code.

If the socket is still open, there will be 0 or more bytes data which I don't actually want to pull out of the socket buffer yet.

I was thinking that I could call int ret = recv(sockfd, buf, 1, MSG_DONTWAIT | MSG_PEEK); to determine if the socket is still connected. If it's connected but there's no data in the buffer I'll get a return of -1 with errno == EAGAIN and return the sockfd for reuse. If it's been gracefully closed by the peer I'll get ret == 0 and open a new connection.

I've tested this and it seems to work. However, I suspect there is a small window between when I recv the last bit of my data and when the peer FIN arrives in which I could get a false-positive EAGAIN from my test recv.

Is this going to bite me, or is there a better way of doing this?

A: 

Do you control the other end? The most reliable way to perform a "clean" shut down of a socket is for the other end to send a "goodbye" message of some sort.

Dean Harding
No, I don't control the other end. However, the other end **should** always send a application level message indicating that they are closing from their end. It's just that in the real world that doesn't always happen. I could treat it like a regular error, but I would like to try and actively catch it most of the time.
Robert S. Barnes
A: 

(Slightly "off topic", sorry). Perhaps this discussion may be helpful four you. It still doesn't answer to you "FIN" question, but may help you to react in a more easy way to the peer shutdown while your program is sending.

Bye

Giuseppe Guerrini
+1  A: 

OK, so I ran some more tests and this is what I found.

I set my client up to send HTTP/1.1 Connection: close messages to the server causing the server to call close after it's last write of data. When my client finished reading data from a GET transaction it would test the socket to see if it was still open using the above method and then attempt to issue another GET.

What I found is that approximately 30% of the time my test would occur before the server's FIN arrived leading to false-positives and failed operations.

Probably the only way to make this reasonably reliable, say close to 99% would be to introduce artificial delays related to the connection latency between the last read and the attempted socket reuse - however, that would pretty much murder performance.

So, I have to conclude that while this tool is useful, it's only marginally so.

Robert S. Barnes
+1 : interesting tests. One can understand why in telecom 90% of the code is for managing exceptional behavior :)
neuro