关于recvfrom接收超时

  recvfrom,这方法如果不特意设置,默认为阻塞模式,如果一直收不到消息,那么会一直阻塞在那里。


如何设置阻塞时间,或者说如何设置recvfrom接收超时时间。可以使用setsockopt。


setsockopt()


setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (char*)&tv, sizeof(timeval))

其中有一个第三个参数可以设置为SO_RCVTIMEO,SO_SENDTIMEO。分别可以设置接收超时和发送超时。那么之后的第四个和第五个参数即为和时间相关的参数,一般使用timeval结构体。


代码示例如下:

WSADATA wsadata;
WSAStartup(0x0202, &wsadata);


SOCKET sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (SOCKET_ERROR == sock)
{
cout << "socket failed" << endl;
WSACleanup();
return 0;
}


sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(9999);
addr.sin_addr.S_un.S_addr = inet_addr("192.168.0.31");


int32_t b = bind(sock, (sockaddr*)&addr, sizeof(addr));
if (b)
{
cout << "bind failed, the error code = " << WSAGetLastError() << endl;
closesocket(sock);
WSACleanup();
return 0;
}


timeval tv = {10, 0};
b = setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (char*)&tv, sizeof(timeval));
if (b)
{
cout << "setsockopt failed" << endl;
closesocket(sock);
WSACleanup();
return 0;
}


sockaddr_in addr_from;
addr_from.sin_family = AF_INET;
int32_t len = sizeof(addr_from);


while (true)
{
char buffer[1024] = {0};
b = recvfrom(sock, buffer, 1024, 0, (sockaddr*)&addr_from, &len);
if (b <= 0)
{
cout << "recvfrom failed, the error code = %d"<< WSAGetLastError() << endl;
break;
}
}

如果超时,那么recvfrom会返回错误码为10060,解释为由于连接方在一段时间后没有正确答复或连接的主机没有反应,连接尝试失败


当然还有一个需要注意的地方,这个设置只能直接作用于recvfrom这个方法,如果说你的接收时写在线程里,并且还有一个select或者是iocp的方法来测试socket的活动,那么这个设置之后想要用来控制recvfrom超时,那么变会无效,所以使用的时候注意一下。

这个时候如果想要控制recvfrom阻塞时间的话,那么就需要另外采用方法了,我使用的方法是另起一个线程,用于监控最新一次接收消息的时间(每次收到新消息即更新一次)和当下系统时间对比,是否超出你的预设超时时间,如果超出,那么关闭socket即可。

你可能感兴趣的:(网络编程学习心得)