具有单个写入器、多个读取器的 Linux IPC



在我的应用程序中,我有一个进程("编写器")从外部硬件读取数据。此过程应向多个"读取器"提供一致的数据包

问题:一个进程如何向多个客户端发送一致的数据包(不阻塞),同时他们看到类似于个人FIFO结束的东西?我使用的是 Debian Linux。

1)在我的第一种方法中,我尝试了">数据报 - unix 域套接字",效果很好。 但是使用"编写器"作为服务器,所有客户端都必须永久轮询服务器。:-( 他们多次收到一个数据包;或者如果轮询速度不够快,则会错过数据包。

2)我的第二种方法是FIFO(命名管道),它也可以工作,但是对于几个读者来说,"奇怪的事情发生了",我在这里得到证实:http://beej.us/guide/bgipc/output/html/multipage/fifos.html

我试了这个,在网上搜索了一整天,但找不到一个合理的答案。

编辑:对不起,我没有提到:我不能使用socketpair()fork。我的程序是独立开发的。我想让作家做好准备,同时培养新的读者。

如果编写器进程是服务器,它可能会fork客户端进程,而只是普通管道(2)进行通信。如果没有父/子关系,请考虑使用 mkfifo(3) 或AF_UNIX套接字(参见 unix(7) 和 scoket(2) ...)制作的命名管道,它们是双向的(AF_UNIX套接字在同一台机器上比 TCP/IP 或 UDP/IP 快得多)。

请注意,编写器进程正在从硬件设备读取数据,并将数据写入或发送到多个读取器客户端。因此,编写器进程同时处理许多文件描述符(要读取的硬件设备,以及要写入客户端的套接字或管道,每个客户端至少一个文件描述符)。

但是,重要的是有一些事件循环(特别是在服务器端,也可能在客户端内部)。这意味着你在循环中调用一些多路复用系统调用,如 poll(2),并在每次迭代中"决定"你是否在读取、写入或连接(以及应该读取、写入或连接哪个文件描述符)。参见 read(2), write(2), connect(2), send(2), recv(2) 等...请注意,您应该使用事件循环缓冲数据(因为readwrite可能位于"部分"或"不完整"消息上)。

请注意,poll在等待 I/O 时不会占用 CPU 资源。你可以,但你不应该再使用一些较旧的多路复用系统调用(比如过时的select(2)...)。使用投票(2)。

您可能希望使用库来提供事件循环,例如 libevent 或 libev...另请参阅此答案。该事件循环还应(在服务器端)轮询,然后读取硬件设备。

如果某些程序正在使用像Qt或Gtk这样的GUI工具包(例如在客户端),那么它们应该从该工具包提供的现有事件循环中受益。

您应该阅读高级 Linux 编程并了解 C10K 问题。

如果信号或定时器很重要(仔细阅读signal(7) 和 time(7)),Linux 特定的 signalfd(2) 和 timerfd_create(2) 可能会非常有用,因为它们可以很好地与事件循环配合使用。这些特定于Linux的系统调用(signalfdtimerfd_create...)太新了,无法在Advanced Linux编程中提及。

顺便说一句,你可以研究与你类似的现有自由软件的源代码,和/或使用 strace(1) 来理解他们正在做的确切的系统调用。

如果你没有围绕多路复用系统调用的循环 (à la poll(2)),那么你就没有事件循环,你的设计有缺陷,不可能可靠地工作(因为你需要一次多个文件描述符做出反应)。

您也可以使用多线程方法,但它要复杂得多,在您的特定情况下不值得付出努力。

ZeroMQ 有针对这个问题的模式。速度快,支持很多编程语言。发布-订阅。请参阅:https://zeromq.org/(免费和开源)。

最新更新