为什么在连接关闭时recv有时不会返回?

时间:2012-10-01 01:43:36

标签: delphi return winsock recv

我有一个简单的winsock客户端/服务器应用程序。大多数情况下一切正常,但有时即使客户端应用程序终止,recv也不会返回值。

来自MSDN:

  

如果没有错误发生,recv返回收到的字节数和   buf参数指向的缓冲区将包含此数据   接收。如果连接已正常关闭,则返回   值为零。否则,返回SOCKET_ERROR的值,并返回a   可以通过调用WSAGetLastError来检索特定的错误代码。

如果没有与客户端的连接,recv永远不会返回并永远挂起的原因是什么?

相关的服务器代码:

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.

2 个答案:

答案 0 :(得分:0)

'如果连接已正常关闭' - 如果没有正常关闭,(有人在客户端拔出网线),服务器recv()调用将继续等待,很可能永远等待。您可以设置KEEPALIVE套接字选项,但默认情况下这将花费很长时间来检测半开套接字,此外,KEEPALIVE超时值是全局注册表值:(

您可以使用SO_RCVTIMEO setsockopt()选项在recv()上设置较小的每插槽超时。您可以使用此超时来立即关闭套接字,或者,如果您的协议允许,则向对等方发出某种轮询/回应请求以确保它仍然存在,如果发生另一个超时,则关闭套接字。

答案 1 :(得分:0)

recv()永远不会阻止正常断开连接(发送FIN数据包的连接)。所以要么它实际上不是一个优雅的断开连接,要么你的读取代码与你的套接字不同步,而你实际上并没有从你认为正在阅读的套接字中读取。