没有 ConnectEx 的 Windows 上的非阻塞套接字连接

Posted

技术标签:

【中文标题】没有 ConnectEx 的 Windows 上的非阻塞套接字连接【英文标题】:Non-blocking socket connect on Windows without ConnectEx 【发布时间】:2011-10-23 13:45:58 【问题描述】:

我需要在单个进程中启动 1000 个 client 连接,我需要解决的关键限制是驱动程序不支持 ConnectEx,因此我无法拥有纯 IOCP 解决方案。

我的第一个想法是处理连接的线程池,其中每个句柄可以使用普通的连接/选择语义处理多达 64 个连接,并且一旦连接就继续使用 IOCP。 但这行不通;一旦选择运行,我就无法向 FD_SET 添加另一个套接字。所以我必须将套接字设置为非阻塞并轮询它们。 最好的解决方案可能是最简单的;每个线程一个连接客户端。假设我可以保持合理的连接率,那么池中的线程数可能会很少。

这是一种奇怪的情况,理想情况下,驱动程序会支持 ConnectEx,但它(目前)不支持,我需要以最好的方式解决它。

还有其他方法吗?

【问题讨论】:

【参考方案1】:

首先,可以使用虚拟套接字(例如,连接到自身的 UDP 套接字)破坏 select,尽管在您的情况下这可能代价高昂。

如果你有一个可以处理周围消息的窗口,你可以使用WSAAsyncSelect 来获取connect 的异步通知。 (请注意,这也会自动使您的套接字非阻塞,这需要再次调用 WSAAsyncSelect 并调用 ioctlsocket 来禁用)。

如果没有这个,您可以使用WSAEventSelect,但您会发现这会将您限制为每次等待 64 个套接字(因为这是WaitForMultipleObjects 的上限)。这也将使您的套接字成为非阻塞的,您可以像为 WSAAsyncSelect 所做的那样撤消它。

(作为一个完整的旁注,您可以通过在包含winsock2.h 之前定义FD_SETSIZE 来增加select 处理的套接字数量)

【讨论】:

WSAAsyncSelect 和 WSAEventSelect 听起来都很有用。我想我将从每个连接一个线程开始,然后使用这两个中的一个将连接池化为 64 个组。谢谢。 我没有注意到 WSAAsyncSelect 使用 Windows 消息。讨厌,但可能很有帮助。

以上是关于没有 ConnectEx 的 Windows 上的非阻塞套接字连接的主要内容,如果未能解决你的问题,请参考以下文章

ConnectEx 与 IOCP 问题

无法连接服务器: dial tcp [::1]:8080: connectex: No connection could be made because the target machine主动拒绝

本地连接不上linux服务器上的Redis

Windows系统下Log4Net+FileBeat+ELK日志分析系统问题总结

Windows搭建Log4Net+FileBeat+ELK日志分析系统过程以及问题总结

Windows 上的“ImportError:没有名为站点的模块”