0

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

引用 MSDN:

如果没有发生错误,recv 返回接收到的字节数,buf 参数指向的缓冲区将包含接收到的数据。如果连接已正常关闭,则返回值为零。否则,返回 SOCKET_ERROR 的值,并且可以通过调用 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.
4

2 回答 2

1

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

于 2012-10-02T00:08:05.650 回答
0

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

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

于 2012-10-01T02:53:16.750 回答