如果在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
的模拟。