Testing for a closed socket

2019-02-12 14:20发布

问题:

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?

回答1:

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.



回答2:

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.



回答3:

(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