C语言 为什么SO_RCVTIMEO在应用于recv() windows套接字时被忽略?



如果在5秒内没有读取数据,我希望阻塞recv()中止。

下面是创建套接字sock并连接到服务器的代码
sock = WSASocket( AF_INET, SOCK_STREAM, IPPROTO_TCP, 0, 0, 0 );
WSAConnect( sock, ptr->ai_addr, sizeof ( struct addrinfo ), NULL, NULL, NULL, NULL )

在调用recv()之前,函数setsockopt()被成功调用。然而,recv()仍然无限期地阻塞?

DWORD timeout = 5 * 1000;
if (setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (char*)&timeout, sizeof(timeout)) == SOCKET_ERROR) {
printf("failed setting socket option GLE %dn", WSAGetLastError());
closesocket(sock);
return INVALID_SOCKET;
}
...
cbRead = recv ( sock, ( CHAR * ) pTemp, cbRemaining, 0 );
...

我找到的唯一解决方法是以下代码,当没有套接字错误或超时时调用recv()

fd_set fds;
FD_ZERO(&fds);
FD_SET(sock, &fds);
struct timeval tv;
tv.tv_sec = 5;
tv.tv_usec = 0;
int ret = select(0, &fds, NULL, NULL, &tv);
if (ret == SOCKET_ERROR || ret == 0) {
printf("TIMEOUT detected on socket=%d ERROR=%dn", s, ret);
return FALSE;
}
...
cbRead = recv ( sock, ( CHAR * ) pTemp, cbRemaining, 0 );
...

忽略SO_RCVTIMEO是否有原因?我更喜欢通过setsockopt直接在套接字上设置超时。

根据SO_RCVTIMEO的详细Winsock文档,

如果套接字是使用WSASocket函数创建的,那么dwFlags参数必须设置WSA_FLAG_OVERLAPPED属性才能使超时正常工作。否则超时不生效。

您显示的WSASocket()调用没有在标志中指定WSA_FLAG_OVERLAPPED,因此您所指定的接收超时不生效的观察结果与文档一致。

还需要注意的是,WSA_FLAG_OVERLAPPED的文档中有

大多数套接字创建时应该设置此标志。

这些细节大多是Winsock特有的。据我所知,POSIX套接字没有或不需要WSA_FLAG_OVERLAPPED的模拟。

相关内容

  • 没有找到相关文章