我有一个简单的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.
2 回答
'如果连接已正常关闭' - 如果它没有正常关闭,(有人在客户端拔出网线),服务器recv()调用将继续等待,很可能永远等待 . 您可以设置KEEPALIVE套接字选项,但默认情况下这将花费很长时间来检测半开套接字,此外,KEEPALIVE超时值是全局注册表值:(
您可以使用SO_RCVTIMEO setsockopt()选项在recv()上设置较小的每插槽超时 . 您可以使用此超时来立即关闭套接字,或者,如果您的协议允许,则向对等方发出某种轮询/回应请求以确保它仍然存在,如果发生另一个超时,则关闭套接字 .
recv()
永远不会阻止正常断开连接(发送FIN
数据包) . 因此,它实际上并不是一个优雅的断开连接,或者您的读取代码与您的套接字不同步,并且您实际上并没有从您认为正在读取的套接字中读取 .