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 ther开发者_如何学Pythone'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?
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.
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.
(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
精彩评论