【问题标题】:timeout for blocking TCP socket not working阻塞 TCP 套接字的超时不工作
【发布时间】:2019-05-15 08:06:04
【问题描述】:

请注意:平台是 Windows,而不是 Linux。

我有一个阻塞的 TCP 客户端套接字。连接远程服务器后,我设置了读取超时(远程服务器不稳定,网络条件不好),然后接收数据。

有时,recv() 函数永远不会返回,我的程序已经死了。

代码如下:

// set timeout
{
    int millisec = 1000;
    if(setsockopt(sock_, SOL_SOCKET, SO_RCVTIMEO, (char*)&millisec, sizeof(int))) {
        MessageBox(0, "setsockopt fail", "", 0);
    }
}

unsigned begin_t = time(0);
int r = recv(sock_, ptr, static_cast<int>(size), 0);
unsigned end_t = time(0);

if(end_t - begin_t > 2) {
    MessageBox(0, "over 2 sec", "", 0); // This MessageBox popups some time
}

我在 recv() 函数之前将套接字超时设置为 1 秒。理论上,recv() 永远不会超过 1 秒。但有时,它仍然需要超过 3 秒,然后出现 MessageBox。

为什么有时超时不起作用?

【问题讨论】:

  • time() 具有秒精度,因此对于时序代码来说不会很准确。请改用GetTickCount/64()QueryPerformanceCounter()
  • 也许我不需要计算时间成本,因为有时它永远不会回来。
  • 当非无限 SO_RCVTIMEO 超时生效时,recv() 根本不可能永远阻塞。所以其他事情正在发生。另外,仅供参考,实现读取超时的另一种方法是在调用 recv() 之前调用 select()
  • 套接字是否具有OVERLAPPED 属性?

标签: sockets winapi socket-timeout-exception winsockets


【解决方案1】:

SO_RCVTIMEO 在阻塞套接字中不受支持。

如果阻塞接收调用超时,则连接处于 不确定状态,应该关闭。如果创建了套接字 使用 WSASocket 函数,则 dwFlags 参数必须具有 WSA_FLAG_OVERLAPPED 属性设置为超时运行 适当地。否则超时永远不会生效。

WSASocketWSA_FLAG_OVERLAPPED 一起使用。或socket()(默认为WSA_FLAG_OVERLAPPED模式)

【讨论】:

  • 关键是WSA_FLAG_OVERLAPPED,我的代码调用setsockopt(INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE,...,如果设置了SO_OPENTYPE,则WSA_FLAG_OVERLAPPED被禁用。详情可以找她:github.com/yhirose/cpp-httplib/issues/150
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-05-31
  • 2012-01-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多