在我的应用程序中,我有一个进程(“编写者”)从外部硬件读取数据。 此过程应向多个“读者”提供一致的数据包。
问题: 一个进程如何在看到类似个人FIFO的结尾时向多个客户端发送一致的数据包(不阻塞)?我在Debian Linux上。
1)在我的第一种方法中,我尝试了“数据报 - unix域套接字”,效果很好。
但是使用“writer”作为服务器,所有客户端都必须永久轮询服务器。 :-(
他们多次得到一个包;如果没有足够快速地进行轮询,则会丢失数据包。
2)我的第二种方法是 FIFO (命名管道)也有效,但是有几位读者“发生了奇怪的事情”,我在这里得到了证实:{{ 3}}
我试过这个,整天搜索网络和stackoverflow,但我找不到合理的答案。
编辑:抱歉,我没有提及:我无法使用socketpair()
和fork
。我的程序是独立开发的。我想在开发新读者的同时准备好作家。
答案 0 :(得分:1)
如果编写者进程是服务器,则可能fork
客户端进行处理,并且只是pipe(2)进行通信。如果没有父/子关系,请考虑使用mkfifo(3)或AF_UNIX
套接字创建的命名管道(请参阅unix(7)和scoket(2) ... 。)双向(AF_UNIX
套接字比同一台机器上的TCP / IP或UDP / IP快得多。)
请注意,您的编写器进程正在从您的硬件设备读取数据,并正在向多个 reader 客户端写入或发送数据。因此,您的编写器进程同时处理许多文件描述符(要读取的硬件设备,要写入客户端的套接字或管道,每个客户端至少有一个文件描述符)。
然而,重要的是有一些event loop (特别是在服务器端,也可能在客户端内)。这意味着您在循环中调用了一些多路复用系统调用,如poll(2),并且“决定”您是在读取还是正在写入或连接(以及应该读取哪个文件描述符,或者应该是在每次迭代中写入或应该连接。另请参阅read(2),write(2),connect(2),send(2),recv(2)等...请注意,您应该使用事件循环缓冲数据(自{{1 }和read
可以是“部分”或“不完整”的消息。)
请注意,write
在等待I / O时没有占用CPU资源。你可以,但你不应该再使用一些旧的多路复用系统调用(就像过时的select(2) ...)。 使用poll(2) 。功能
您可能希望使用库来提供事件循环,例如libevent或libev ...另见this answer。那个事件循环也应该(在服务器端)轮询然后读取硬件设备。
如果某些程序正在使用GUI工具包(例如在客户端),如Qt或Gtk,那么他们应该从该工具包提供的现有事件循环中获利......
您应该阅读Advanced Linux Programming 并了解C10K problem。
如果信号或计时器很重要(仔细阅读 signal(7)和time(7)),那么特定于Linux的signalfd(2)和timerfd_create(2)可能会非常有用他们很好地使用事件循环。这些特定于Linux的系统调用(poll
& signalfd
...)太新了,无法在高级Linux编程中提及。
如果您没有围绕多路复用系统调用(例如poll(2))的循环,那么您没有事件循环,并且您的设计存在错误,并且无法可靠且可靠地工作(因为您需要立即对几个文件描述符做出反应)。
您也可以使用多线程方法,但它更复杂,在您的特定情况下不值得付出努力。
答案 1 :(得分:0)
ZeroMQ具有解决此问题的模式。快速并且支持许多编程语言。 Pub-Sub。请参阅:https://zeromq.org/(免费和开源)。