Reputation: 109
I have a simple winsock client/server application. Mostly everything works fine, but sometimes recv does not return a value even when the client application is terminated.
Quote from MSDN:
If no error occurs, recv returns the number of bytes received and the buffer pointed to by the buf parameter will contain this data received. If the connection has been gracefully closed, the return value is zero. Otherwise, a value of SOCKET_ERROR is returned, and a specific error code can be retrieved by calling WSAGetLastError.
What could be the reason for that recv never returns and hangs forever without a connection to the client?
The relevant server code:
const
BUFSIZE = 512;
var
Sock: TSocket;
I : Integer;
Buf : AnsiString;
begin
repeat
SetLength(Buf, BUFSIZE);
//blocking call
I := recv(Sock, Pointer(Buf)^, BUFSIZE, 0);
if I > 0 then
begin
SetLength(Buf, I);
//do s.th. with Buf
end;
until I <= 0; //Connection closed or error
//Sometimes never here
Synchronize(procedure
begin
FOnConnectionClosed(Self, Sock, WSAGetLastError);
end);
end.
Upvotes: 0
Views: 2766
Reputation: 595467
recv()
will never block on a graceful disconnect (one that sends a FIN
packet). So either it is not actually a graceful disconnect, or your reading code is out of sync with your socket, and you are not actually reading from the socket you think you are reading from.
Upvotes: 1
Reputation: 24847
'If the connection has been gracefully closed' - if it's not gracefully closed, (someone pulls out network cable at the client), the server recv() call will continue to wait, quite possibly for ever. You can set the KEEPALIVE socket option, but this will take a long time by default to detect a half-open socket, also, the KEEPALIVE timeout value is a global registry value:(
You can use the SO_RCVTIMEO setsockopt() option to set a smaller, per-socket timeout on recv(). You can use this timeout to either close your socket immediately or, if your protocol allows it, to issue some sort of poll/echo request to the peer to ensure it's still there and, if another timeout occurs, close the socket.
Upvotes: 1