【问题标题】:Multiple threads for multiple ports?多个端口的多个线程?
【发布时间】:2009-09-27 02:06:10
【问题描述】:

我有一个程序(进程)需要监听 3 个端口……两个是 TCP,另一个是 UDP。

两个 TCP 端口将每隔一段时间接收大量数据(可能每 5 分钟一次或每 20 秒一次)。第三个 (UDP) 端口正在接收常量数据。现在,让这些在不同的线程上监听有意义吗?

例如,当我从一个 TCP 端口接收大量数据时,我不希望我的 UDP 流中断......这些是网络编程的常见问题吗?

如果有任何影响,我将在 Windows 上使用 Boost 库。

我只是在寻找有关此问题以及如何管理多个连接的想法/想法/指导。

【问题讨论】:

  • 我建议您遵循“boost:asio/select/Windows Completion Port API”和“线程池”答案之一的建议(并将其标记为正确)。请注意,对于您的应用程序,每个端口执行 1 个线程是最简单的实现。虽然您可能会说今天您永远不需要超过 4-6 个套接字,但有一天您可能需要这个应用程序来扩展到更多的套接字。因此,您可能会在今天使用线程池为自己(或跟随您的人)省去很多麻烦。
  • 对这个问题的回答有点刺激。每个人似乎都认为您想构建一个 Web 服务器。我不知道答案(这就是为什么这只是一个评论),但我怀疑如果 UDP 流的吞吐量很高,并且你想避免丢弃 UDP 数据包,你真的希望它能够运行在不同的处理器上。

标签: c++ networking boost network-programming


【解决方案1】:

一般来说,除非必要,否则请避免使用线程。在现代机器上,您将通过使用单线程和使用 I/O 就绪/完成功能获得更好的性能。在 Windows 上,这是 IO Completion Ports,在 Mac OS X 和 FreeBSD 上:kqueue(2),在 Solaris 上:事件端口,在 Linux epoll 上,在 VMS QIO 上。等等。

在 boost 中,这是由 boost::asio 抽象出来的。

线程有用的地方是您必须进行重要处理或执行阻塞操作系统调用的地方,这会给网络处理的其余部分增加不可接受的延迟。

【讨论】:

  • 这是错误的。如果你试图让一个线程来处理多个套接字,你的性能会很糟糕。
  • 垃圾!当您扩大套接字数量时,如果每个套接字都有一个线程,性能将显着下降。这种架构有很多例子,包括大多数现代 Web 服务器。对于较早的知名考试,请参阅:kegel.com/c10k.html您是否真的尝试过扩大这些内容?
  • 作为一个尝试过windows IO Completion 端口的人,我可以说请不要折磨自己,使用boost.asio...
【解决方案2】:

使用线程,每个接收连接一个,将有助于保持高吞吐量并防止一个端口的数据阻塞另一个端口的处理。

这是个好主意,特别是因为您说的是只有 3 个连接。产生三个线程来处理通信将使您的应用程序更容易维护和保持性能。

【讨论】:

    【解决方案3】:

    首先,

    ...这些是网络编程的常见问题吗?

    是的,线程问题是网络编程中非常常见的问题。

    其次,您使用三个线程侦听三个不同端口的设计理念会奏效,允许您同时侦听所有三个端口。正如 cmets 中所指出的,这不是唯一的方法。

    最后,网络编程中常见的一种设计是让一个线程监听连接,然后生成一个新的辅助线程来处理连接。最初的监听线程只是将套接字连接传递给助手,然后再返回监听新连接。

    【讨论】:

    • 你不需要多个线程来监听不同的端口。使用 select() 或等效方法等待所有侦听套接字上的输入事件。
    • 是 Boost 中的 select() 吗?如果没有,您能否将我指向此功能的文档,以便我可以找到一个 boost equiv?谢谢卡伦斯基
    • 选择来自您的操作系统。在 boost 中,请参阅在其实现中使用 select(如果适用)的 asio 库。
    • Select 是原始 BSD 套接字 API 的一部分,并在 Windows 和类 Unix 操作系统中实现。检查 MSDN 或手册页。 Boost::asio 是一个围绕 select() 和其他等效异步 IO API 的跨平台抽象。
    【解决方案4】:

    多线程无法扩展。操作系统线程在数千或数万个连接的规模上太重了。当然,你只有 3 个,所以没什么大不了的。事实上,如果您确定您的应用程序不需要扩展,我什至可能会以简单的名义在您的情况下推荐它。

    但在规模上,您会想使用select()/poll()/epoll()/libevent/etc。在现代 Linux 系统上,epoll() 是迄今为止最健壮的并且速度极快。一个线程同时轮询所有套接字上的套接字就绪情况,然后发出就绪信号的套接字要么立即由单个线程处理,要么通常不移交给线程池。线程池的线程数量有限(通常是本地机器上可用计算核心数量的某个比例),其中只要套接字准备好,就会获取空闲线程。

    同样,您可以为每个连接使用一个线程,但如果您有兴趣了解构建可扩展网络系统的正确方法,请不要这样做。构建一个 select()/poll() 风格的服务器是一种很棒的学习体验。

    参考见C10K问题:

    http://www.kegel.com/c10k.html

    【讨论】:

    • 它可能扩展到 4 或 5 个连接......最多可能 6 个。此应用程序在使用中相当具体。感谢您的提示!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-11-05
    • 1970-01-01
    • 2021-10-28
    • 1970-01-01
    • 2012-08-04
    • 1970-01-01
    • 2011-03-02
    相关资源
    最近更新 更多