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