winsock select 报告 10022 错误(原因不明,需要 tcp/winsock 大师帮助)

winsock select reports an 10022 error (by a reason that is not obvious, need tcp/winsock guru help)

给定(简化的代码):

const timeval timeout = {100, 0};
for(;;)
{
    fd_set sockets = {2, {service, controlSocket}};
    const auto result = select(0, &sockets, nullptr, nullptr, &timeout);
    ...
    if (result > 0 && FD_ISSET(service, &sockets))
    {
        auto workerConnection = accept(service, nullptr, nullptr);
        WSARecv(workerConnection, ...);
    }
}

其中service是处于监听状态的socket,controlSocket是service socket上最先建立的传入连接,用于与manager通信。

错误 10022 仅当任何先前建立的工作连接在远程端正常关闭时才会发生。我强调 此代码几乎所有时间都按预期工作 除了工作应用程序关闭连接,但是,我并不声称在远程端关闭连接会影响此行为。我刚刚注意到这个错误恰好发生在远程端关闭连接之后,而服务端报告 WAIT_CLOSE 一个已建立的连接。我再重复一遍,这段代码工作正常,在循环的下一个循环出现错误之后,直到另一个套接字关闭 select 工作,完全没有错误。 error的数量等于建立的workerConnections的数量。

不知道这是否重要我在同一台 PC 上测试了此代码 运行 管理器、服务和辅助应用程序,而不是使用 localhost 我提供了 PC 的网络名称来建立连接。在与 worker 服务建立连接后,应用程序仅通过 workerConnection 异步接收和发送数据。

问题:由于它根本不影响服务功能,而且我没有任何其他 WSA 错误,可以忽略此错误并避免垃圾邮件日志吗?问题?我怀疑 WSA 中存在某种问题,因为错误仅在非常特定的情况下发生。我对么?

要么我无法正确阅读 MSDN 文档,要么不清楚但我的代码中存在重大问题。 MSDN 说:

Note When issuing a blocking Winsock call such as select with the timeout parameter set to NULL, Winsock may need to wait for a network event before the call can complete. Winsock performs an alertable wait in this situation, which can be interrupted by an asynchronous procedure call (APC) scheduled on the same thread. Issuing another blocking Winsock call inside an APC that interrupted an ongoing blocking Winsock call on the same thread will lead to undefined behavior, and must never be attempted by Winsock clients.

Note The shutdown function does not block regardless of the SO_LINGER setting on the socket.

从我的角度来看,他们想说什么非常不清楚,但问题是当我用超时阻塞调用 select 时,即使 MSDN 声称它没有阻塞,windows 可以同时执行我在 WSARecv 中提供的回调。在那个回调中,我 做了 另一个同步 Winsock 调用 - 关闭,即使 MSDN 声称它没有阻塞。所以我的原始代码完全符合 MSDN 中指出的导致未定义行为的情况。我最初的问题是在我测试调试配置时出现的,并且只有一个问题。在我开始测试发布配置后,我发现了更多问题。

尽管我无法提供对 MSDN 的引用,但我得出以下结论(这比上面提供的 MSDN 说明清楚得多):

您不能在重叠操作完成后从 windows 调用的回调内部调用任何 Winsock 函数,除了那些具有 LPOVERLAPPED 输入参数且此参数必须不能为 NULL。 另一方面,您可以调用其他不使用 Winsock 的阻塞 windows 函数。