6

为了工作,我需要编写一个 tcp 守护进程来响应我们的客户端软件,并且想知道是否有人对解决此问题的最佳方法有任何提示。

我应该像通常使用线程一样为每个新连接分叉吗?

4

7 回答 7

10

这取决于您的应用程序。线程和分叉都可以是完全有效的方法,也是单线程事件驱动模型的第三种选择。如果您可以详细解释您正在写的内容,那么在提供建议时会有所帮助。

对于它的价值,这里有一些一般准则:

  • 如果您没有共享状态,请使用分叉。
  • 如果您有共享状态,请使用线程或事件驱动系统。
  • 如果您需要在大量连接下获得高性能,请避免分叉,因为它具有更高的开销(尤其是内存使用)。相反,使用线程、一个事件循环或多个事件循环线程(通常每个 CPU 一个)。

通常分叉将是最容易实现的,因为一旦分叉,您基本上可以忽略所有其他连接;由于额外的同步要求,线程次之;由于需要将您的处理转换为状态机,因此事件循环更加困难;并且多个线程运行事件循环是其中最困难的(由于结合了其他因素)。

于 2009-07-31T04:05:46.617 回答
4

我建议任何一天都通过线程分叉连接。线程的问题在于共享内存空间,以及操作另一个线程的内存是多么容易。对于分叉的进程,进程之间的任何通信都必须由您有意完成。

刚刚搜索并找到了这个答案:fork 的目的是什么?. 您显然知道答案,但该线程中的#1 答案对 fork() 的优点有很好的说明。

于 2009-07-31T04:06:51.653 回答
1

除了@hobodave 的好答案之外,“每个连接分叉”的另一个好处是您可以通过使用inetdortcpserver或类似的方法非常简单地实现您的服务器:然后您可以使用标准输入和标准输出与套接字进行通信,并且不要不必进行任何侦听套接字管理(侦听连接等)等。

于 2009-07-31T04:10:38.573 回答
1

当然,另一种选择是预先分叉多个守护进程副本,并让每个副本保持活动状态并继续响应请求。这完全取决于您的应用程序、预期负载和性能要求等。

最简单最简单的方法是编写一个基于inetd的守护进程;您的软件可以忽略它通过 TCP 连接运行的事实,而只需通过标准输入/标准输出处理输入/输出。这在绝大多数情况下都很有效。

于 2009-07-31T04:13:00.987 回答
1

如果您不打算每秒处理许多新连接,请考虑从 inetd 运行。除此以外...

下载 OpenSSH 源代码。他们在权限分离方面做了很多工作,恰到好处,它是可移植的,而且它的安全性受到了比其他任何东西都多的审查。

根据您的需要调整它,您可能可以扔掉大部分。当然要遵守许可协议。遵循具有良好 SCC 的未来补丁。

在你有充分的证据证明这是一个真正的问题之前,不要担心分叉进程与线程的性能。Apache 多年来一直使用简单的每客户端进程模型来运行最繁忙的站点。

如果你真的有野心,你可以使用某种非阻塞异步 IO 模型。我喜欢 Boost.Asio,但我对 C++ 很感兴趣。

确保您的代码正确处理信号。HUP 重新加载配置。TERM 正常关闭。

不要尝试编写自己的日志文件。仅使用 syslog,或者只写入可以重定向到 syslog 的 stderr。尝试在所有日志略有不同的家用服务器上设置 logrotate 真的很痛苦。

于 2009-07-31T04:25:15.720 回答
1

如果您想避免一起使用线程/分叉,我建议将所有非阻塞 I/O 与libevent一起使用。Libevent 是众所周知的事件驱动编程的高性能解决方案。

于 2009-07-31T16:42:39.670 回答
0

查看ACE (C++/Java)。它有许多线程、事件和分叉 TCP 反应器,可满足您的通信需求。您还可以查看Boost ASIO做类似的事情

于 2009-07-31T17:03:20.940 回答