【问题标题】:WSAPoll vs Overlapped WSARecv Performance?WSAPoll 与重叠的 WSARecv 性能?
【发布时间】:2022-10-24 08:34:49
【问题描述】:

我正在创建一个必须处理 1000 多个客户端的服务器,我目前使用的方法是:

一个线程将使用WSAAccept 处理传入连接,它有一个线程池,其中每个线程将使用WSAPoll 一次处理多个客户端。

例如,如果 Client 刚刚连接,Server 会找到一个空闲的 poller 线程并将其添加到该 poller 线程的WSAPoll 的 fdset 中,这样 poller 线程将处理新的 Client 连接。

poller 线程将使用非阻塞 WSAPoll 来处理连接,但随后它将使用(阻塞)recv() 来接收数据包。

Server: WSAAccept
    Thread Poller #1: WSAPoll [1, 2, 3, 4, 5]  // max out
        recv[1, 2, 3, 4, 5]
    Thread Poller #2: WSAPoll [6, 7, 8, 9, 10] // max out
        recv[6, 7, 8, 9, 10]
    Thread Poller #3: WSAPoll [11, 12]         // free
        recv[11, 12]
    // create more pollers if all maxed out

它对我来说工作得很好,但后来我遇到了一个(可能是)更好的解决方案WSARecv 重叠的套接字.

这里的想法是使用非阻塞 WSARecv 完成回调而不是 WSAPoll

    CompletionCallback(){ WSARecv(socket, CompletionCallback); }
Loop:
    socket = WSAAccept();
    WSARecv(socket, CompletionCallback); // CompletionCallback will handle the connection.

因此无需多线程和/或WSAPoll 我做了一个 PoC,它似乎工作得很好,但它是单线程的,我想知道与旧方法相比,它的性能如何。

谢谢!

【问题讨论】:

  • 与所有性能问题一样:您必须对其进行分析并检查它对于您的用例是否足够快。尽管只使用一个线程,但您不可避免地会遇到性能壁垒——就原始吞吐量而言,单个线程只能处理这么多。您将获得的性能将取决于很多因素(每个连接每秒需要处理多少数据,一次将有多少连接处于活动状态,服务器的硬件等......) - 唯一的方法您可以通过对其进行分析来确定它会足够快。
  • 一般来说,如果您需要一个真正高性能的套接字服务器,我建议您使用I/O Completion Ports - 它们也适用于完成回调,但是您可以拥有一个专用于处理完成的整个线程池,而不是在单个线程上运行它们。
  • AcceptEx 也非常有用,因为它允许您一次批量处理 3 个操作(接受连接、获取本地和远程地址以及读取第一个数据块) - 另外它使用重叠 i/o,因此可以完美运行带有完成端口。 (您还可以针对同一个套接字设置多个待处理的AcceptEx,以准备突发的传入连接请求)
  • 感谢您提供有用的信息,我也考虑过使用线程池。不幸的是,由于我的特殊需要,我不能使用任何其他框架,必须自己编写
  • 仅供参考,WSAPoll() is broken,所以无论如何你都不应该使用它。

标签: c++ networking server tcp winsock


【解决方案1】:

OVERLAPPED I/O 的扩展性非常好——缩小/放大/缩小。我的工具使用带有 OVERLAPPED I/O + Nt Threadpool 的 AcceptEx。它可以很好地扩展到数十万个连接。 https://github.com/Microsoft/ctsTraffic

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-04-30
    • 1970-01-01
    • 2012-04-09
    • 2020-12-30
    • 2012-02-09
    • 2013-10-23
    • 2012-12-11
    相关资源
    最近更新 更多