【问题标题】:UDP socket select() returns 1 without delay (timeout) under some conditionsUDP socket select() 在某些情况下无延迟(超时)返回 1
【发布时间】:2018-12-09 12:24:22
【问题描述】:

我在开发客户端应用程序时遇到了问题。

我想在我的应用程序中使用非阻塞 UDP 套接字与服务器通信。我在 Windows 上使用 winsock2 库。

但是...由于某种原因,在某些情况下,select() 函数的行为很奇怪:

  1. 套接字没有绑定地址和端口(它是客户端套接字,所以不需要它)。
  2. select() 之前,我通过sendto 调用将数据发送到我的本地 地址和某个端口。
    • 例如:192.168.1.2

在这些条件下select() 立即(甚至无需等待超时)返回1。就像我准备好接收一些数据包一样。 但是如果调用recvFrom,那么它肯定会返回-1


  1. 如果我将数据包从客户端发送到任何其他地址(这不是我在 LAN 上的地址),那么 select() 将按预期工作。
  2. 如果在调用 select() 之前不向任何地址发送任何数据包,select() 也可以正常工作。

套接字初始化方法:

bool CUdpSocket::initialize()
{
  _handle = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);

  ... error processing code, returns false if error...
}

使用select() 的方法。此方法适用于服务器套接字(具有绑定地址和端口)。

bool CUdpSocket::waitData(s32 timeout_ms)
{
    fd_set readset;
    int result;
    struct timeval tv;

    // Initialize the set.
    FD_ZERO(&readset);
    FD_SET(_handle, &readset);

    // Initialize time out struct.
    tv.tv_sec = 0;
    tv.tv_usec = timeout_ms * 1000;

    result = select(_handle + 1, &readset, NULL, NULL, &tv);

    // Timeout with no data.
    if (result == 0) {
        return false; // Get out of here!
    }

    // Error.
    if (result < 0) {
        // TODO: Maybe throw exception or do something.
        return false;
    } else if (!FD_ISSET(_handle, &readset)) {
        return false; // No data!
    }

    // There is some data!
    return true;
}

【问题讨论】:

标签: c++ sockets udp winsock2


【解决方案1】:

如果您从未绑定的 UDP 套接字发送数据包,操作系统将为您选择一个已使用的端口并将套接字绑定到该端口 - UDP 协议要求发送端口具有地址发送自。

因此,如果您发送的数据包导致响应,那么 select 返回 1 是非常有意义的——这就是对您发送的数据包的响应。

【讨论】:

  • 正如我所写。问题是......即使服务器应用程序没有启动(没有响应),我也会不断地返回1select() 立即返回 1。超时到期时无需等待。仅当我发送请求地址的地址是我的 LAN 地址时才会发生这种情况。
  • 如果服务器没有运行,您可能会收到来自操作系统的 ICMP 错误响应。在这种情况下,这可能会在接收套接字上显示为错误。
猜你喜欢
  • 2016-09-08
  • 2016-11-04
  • 2015-08-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-12-27
  • 2010-12-31
  • 2019-02-16
相关资源
最近更新 更多