2009-07-31 28 views
4

为了工作,我需要编写一个tcp守护进程来响应我们的客户端软件,并想知道是否有任何关于此方面最佳途径的提示。写一个linux守护进程的最佳方式

我应该为每个新的连接分叉,因为通常我会使用线程?

回答

9

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

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

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

一般来说分叉是最容易实现的,因为一旦你分叉,你基本上可以忽略所有其他连接;由于附加的同步要求,线程下一个最困难;事件循环由于需要将处理转变为状态机而变得更加困难;并且多线程运行事件循环最困难(由于结合了其他因素)。

+0

分叉的内存开销并不算太坏,因为进程内存复制拷贝的方式。主要的缺点是fork()花费的时间,但是如果你不创建和销毁不应该成为showstopper的高频连接。 – caf 2009-07-31 05:05:25

+0

是的,但它可能比具有文件描述符和输入缓冲区的小结构多得多:) – bdonlan 2009-07-31 17:23:13

3

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

刚刚搜索并找到答案:What is the purpose of fork?。你显然知道答案,但该线程中的#1答案在fork()的优点上有很好的观点。

+1

另一个好处是中止线程可能会搁浅或崩溃整个应用程序。正如另一个答案中所建议的那样,您可以设置一个工作进程池。考虑有一个简单的委托者进程来排队工作进程协同工作。这种设置可以更好地控制系统资源。 – 2009-07-31 17:24:05

1
从@ hobodave的很好的答案

除了中,“每个连接分叉”的另一个好处是,你可以实现你的服务器非常简单,通过使用inetdtcpserver或类似:那么你可以使用标准输入输出进行通信,插座,并且不必做任何监听套接字管理(侦听连接等)等。

1

另一种选择当然是预分配守护进程的几个副本并让每个副本停留活着并继续回答请求。这一切都取决于您的应用程序,预期的负载和性能要求等。

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

1

如果您不打算每秒钟敲入许多新连接,请考虑从inetd运行。否则...

下载OpenSSH源代码。他们在权限分离方面投入了大量工作,它具有可移植性,并且它的安全性已经超过其他任何方面。

适应你的需求,你可能会扔掉它的大部分。遵守当然的许可协议。使用良好的SCC跟踪未来的补丁。

不要担心分叉进程vs线程的性能,除非你有充分的证据表明这是一个真正的问题。 Apache只用简单的每个客户端模型就能运行最繁忙的站点多年。

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

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

不要试图编写自己的日志文件。仅使用系统日志,或者只写入可以重定向到syslog的stderr。试图在家庭服务器上设置logrotate是一种真正的痛苦,所有日志的记录都略有不同。

1

如果你想避免所有的线程/叉,我建议使用所有非阻塞I/O以及libevent。 Libevent作为事件驱动编程的高性能解决方案而广为人知。

0

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