Winsock2 select() returns WSAEINVAL(错误 10022)

Winsock2 select() returns WSAEINVAL (error 10022)

我有给定的代码:

#include <winsock2.h>
#include <sys/time.h>
#include <iostream>

int main()
{
    WSADATA wsaData;
    if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
    {
        std::cout << "WSA Initialization failed!" << std::endl;
        WSACleanup();
    }

    timeval time;
    time.tv_sec = 1;
    time.tv_usec = 0;
    int retval = select(0, NULL, NULL, NULL, &time);
    if (retval == SOCKET_ERROR)
    {
        std::cout << WSAGetLastError() << std::endl;
    }

    return 0;
}

它打印10022,这意味着错误WSAEINVAL。根据 this page,只有在以下情况下我才会收到此错误:

WSAEINVAL: The time-out value is not valid, or all three descriptor parameters were null.

但是,我看到一些调用 select() 时没有任何 FD_SET 的示例。有可能吗?我需要在客户端代码中执行此操作,让程序在未连接到服务器时短时间休眠。

来自臭名昭著的冒犯Winsock 'lame list':

Calling select() with three empty FD_SETs and a valid TIMEOUT structure as a sleezy delay function.

Inexcusably lame.

注意拼写错误。该文件值得一读,如果你能忍受的话,只是为了看看狂妄自大可以达到令人难以置信的深度。万一他们放弃了,或者发现套接字不是他们发明的API,您可以尝试使用空 FD 集而不是空参数,但我不抱太大希望。

However, I have seen a few examples calling select() without any FD_SETs.

它适用于大多数 OS(不是 Windows)。

Is it possible somehow [under Windows]?

不是直接的,但是很容易围绕 select() 滚动您自己的包装器,即使在 Windows:

下也能为您提供您想要的行为
int proper_select(int largestFileDescriptorValuePlusOne, struct fd_set * readFS, struct fd_set * writeFS, struct fd_set * exceptFS, struct timeVal * timeout)
{
#ifdef _WIN32
   // Note that you *do* need to pass in the correct value 
   // for (largestFileDescriptorValuePlusOne) for this wrapper
   // to work; Windows programmers sometimes just pass in a dummy value, 
   // because the current Windows implementation of select() ignores the 
   // parameter, but that's a portability-killing hack and wrong, 
   // so don't do it!
   if ((largestFileDescriptorValuePlusOne <= 0)&&(timeout != NULL))
   {
      // Windows select() will error out on a timeout-only call, so call Sleep() instead.
      Sleep(((timeout->tv_sec*1000000)+timeout->tv_usec)/1000);
      return 0;
   }
#endif

   // in all other cases we just pass through to the normal select() call
   return select(maxFD, readFS, writeFS, exceptFS, timeout);
}

...然后只需调用 proper_select() 而不是 select() 就可以了。