tim93
tim93

Reputation: 109

why does recv sometimes not return when connection is closed?

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

Answers (2)

Remy Lebeau
Remy Lebeau

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

Martin James
Martin James

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

Related Questions