设置套接字超时不起作用。
设置套接字超时不起作用。
我正在使用setsockopt()
函数来设置recvfrom()
函数的超时时间。由于我使用的协议的特殊性,我需要先设置2秒的超时时间,然后是4秒、6秒,直到达到最大值。但是当我使用这个函数时,似乎超时时间只有0.01秒,因为它发送了8个数据包而没有等待。
//更多变量和代码 struct timeval timeout = {2, 0}; while(1){ setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (char*)&timeout, sizeof(struct timeval)); temp2 = recvfrom(sock, &buff, sizeof(buff), 0, (struct sockaddr *)&addr_server, sizeof(addr_server)); if(temp2 < 0){ /* 超时 */ temp = sendto(sock, (struct udp_PDU*)®_pdu, sizeof(reg_pdu), 0, (struct sockaddr *)&addr_server, sizeof(addr_server)); if(temp == -1){ printf("发送失败\n"); exit(-1); } packet_counter++; debug("发送注册请求包"); if(packet_counter == 8) break; if((interval * max) > t ) timeout.tv_sec+=interval; }else{ /* 接收到数据 */ correct = 1; break; } }
设置套接字的超时时间不起作用的原因是超时不是延迟语句,而是一种防止recv()
或recvfrom()
等调用无限期阻塞的方法。如果数据传输在超时设置之前出现,那就更好了。函数接收到数据后,程序流程继续执行。超时设置为2秒,如果没有任何操作发生,它会停止等待,使程序继续执行,即不再阻塞。没有超时,recv()
或recvfrom()
等函数可能会永远阻塞。
如果你想在recvfrom()
和sendto()
调用之间强制使用2秒间隔(或阻塞),请在循环中的某个位置添加sleep(2);(在Windows上使用Sleep(2000);)。可能是在底部。
while(1){ ... } sleep(2); //or on Windows, Sleep(2000); }
顺便说一下,习惯性地检查任何具有返回值的函数的返回值是一个好习惯,特别是如果该函数的失败会对代码的其余部分产生严重影响。例如:
if (setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (char*)&timeout, sizeof(struct timeval)) < 0) { perror("Error"); } ...
与此相关的几个话题:
- 这篇帖子中描述了更精确的sleep间隔控制选项。
- 在这些帖子中讨论了使用poll()的结构:Sockets using poll()和select() with sockets(第二个更倾向于使用poll())。
- 在这个SO问题中讨论了使用select()函数。