UDP套接字select()在某些情况下无延迟地返回1(超时)

时间:2018-06-30 16:01:58

标签: c++ sockets udp winsock2

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

我想在应用程序中使用非阻塞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;
}

1 个答案:

答案 0 :(得分:0)

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

因此,如果您要发送的数据包产生了响应,那么选择返回1就是很有意义的-这就是对您发送的数据包的响应。