【问题标题】:Windows - Wait on event and socket simulatenouslyWindows - 同时等待事件和套接字
【发布时间】:2017-06-04 05:25:27
【问题描述】:

我正在编写 Win32-API C 代码,它需要等待新的 TCP 连接,另一方面可以随时被任何其他进程/线程关闭。

因此,我需要在停止事件上以某种方式 WaitForSingleObject 并同时等待使用 WSAAccept 的连接。

我在套接字和句柄上都尝试了 WaitForMultipleObjects,但新连接不会触发该函数(套接字上的 WaitForSingleObject 也不会在新连接上触发)。

有什么想法吗?

【问题讨论】:

  • 你需要使用AcceptEx 而不是WSAAccept - 这个api是异步的。你根本不需要等待它。如果您将套接字(第二个参数)绑定到 IOCP - 连接完成时您会收到回调

标签: c windows sockets winapi ipc


【解决方案1】:

您需要使用WSAWaitForMultipleEvents。对于套接字,这里有一些伪代码:

HANDLE hEvent[1];
hEvent[0] = WSACreateEvent();
WSAEventSelect(hSocket, hEvent[0], FD_READ | FD_WRITE);

while (WSAWaitForMultipleEvents(...)) {
    if (WSAEnumNetworkEvents(...)) { // Multiple events max exist
        if (... & FD_ACCEPT) {
        }
        if (... & FD_WRITE) {
        }
        ....
    }
}

如果您使用多个事件(例如,停止事件来指示线程停止),请使用 WSAWaitForMultipleEvents 的返回值来确定发出信号的事件(就像使用 WaitForMultipleObjects 一样)。

【讨论】:

  • 这只让您等待 WSA 套接字事件,而不是标准的 Win32 事件对象,因此您必须使用 WSA 套接字事件来处理停止事件,然后您可以等待所有事件以及WSAWaitForMultipleEvents()。如果要为停止事件使用标准事件对象,则必须使用重叠 I/O 或 IOCP 进行套接字操作(AcceptEx()WSARecv()WSASend() 等),以便您可以分配标准事件对象到每个操作,然后你可以使用WaitForMultipleObjects()
  • WSAWaitForMultipleEvents 的事件数组可以处理多种类型('该数组可以包含不同类型对象的句柄'是文档所说的)。 WSACreateEvent 文档补充说:“如果 Windows 应用程序想要使用自动重置事件而不是手动重置事件,则应用程序可以直接调用 CreateEvent 函数”。
【解决方案2】:

您不能直接等待套接字句柄。

WSAAccept() 是同步的,中止它的唯一方法是关闭监听套接字。

对于您尝试执行的操作,请改用 AcceptEx(),它是异步的,并且支持重叠 I/O 和 I/O 完成端口。

如果您使用重叠 I/O,您可以将标准 Win32 事件对象关联到每个支持重叠 I/O 的套接字操作(AcceptEx()WSARecv()WSASend() 等),并使用标准 Win32 事件停止事件的对象。然后您可以使用WaitForMultipleObjects() 循环来了解哪些事件已发出信号并采取相应措施。

如果您使用 I/O 完成端口,则根本不需要事件对象。您可以将每个套接字与单个 IOCP 队列相关联,并且每当每个支持 IOCP 的套接字操作完成时,都会通知您的 IOCP 处理程序(对GetQueuedCompletionStatus() 的调用或回调函数)。然后,您可以使用PostQueuedCompletionStatus() 将自定义停止消息发布到 IOCP 队列。您的 IOCP 处理程序可以根据它接收到的事件类型采取相应的行动。

【讨论】:

  • use PostQueuedCompletionStatus() to post a custom stop message to the IOCP queue - 我们可以通过BindIoCompletionCallbackCreateThreadpoolIo 将套接字绑定到系统处理的队列 - 这个队列不需要停止并且有自己的处理程序。但是,如果使用自创 IOCP - 需要创建几个工作线程来处理此 IOCP(通常线程数 == 处理器数) - 所以需要调用 PostQueuedCompletionStatus 不是一次,而是线程数 - 通知每个线程停止。
猜你喜欢
  • 2012-01-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-05-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多