在Unix上命名管道(FIFO)与多个读者

时间:2009-10-28 00:46:34

标签: unix fifo

我有两个程序,Writer和Reader。

我有一个从Writer到Reader的FIFO,所以当我在Writer中写入stdin的东西时,它会从Reader打印到stdout。

我尝试打开两个读者,并且只从两个Reader程序中的一个输出到stdout。每次运行时,Unix选择打印标准输出的读者程序似乎是任意的,但是一旦选择其中一个程序,每个输出到标准输出都会从同一个读取程序中打印出来。

有谁知道为什么会这样?

如果我有两个WRITER程序,它们都可以写入同一个管道。

5 个答案:

答案 0 :(得分:25)

FIF O 中的O表示“out”。一旦你的数据“出局”,它就消失了。 :-)所以很自然地,如果另一个进程出现而其他人已经发出了一个读数,那么数据将不会出现两次。

要完成你的建议你应该看看Unix域套接字。 Manpage here。您可以编写一个可以写入客户端进程的服务器,并绑定到文件系统路径。另请参阅socket()bind()listen()accept()connect(),所有这些内容都将与PF_UNIX AF_UNIX一起使用,{{ 1}}和struct sockaddr_un

答案 1 :(得分:10)

Linux tee()可能适合您的需求。
tee

注意:此功能是特定于Linux的。

答案 2 :(得分:2)

我不认为你观察到的行为不仅仅是巧合。考虑这个跟踪,它使用'sed'作为两个读者,并使用循环作为编写者:

Osiris JL: mkdir fifo
Osiris JL: cd fifo
Osiris JL: mkfifo fifo
Osiris JL: sed 's/^/1: /' < fifo &
[1] 4235
Osiris JL: sed 's/^/2: /' < fifo &
[2] 4237
Osiris JL: while read line ; do echo $line; done > fifo < /etc/passwd
1: ##
1: # User Database
1: #
1: # Note that this file is consulted directly only when the system is running
1: # in single-user mode. At other times this information is provided by
1: # Open Directory.
1: #
1: # This file will not be consulted for authentication unless the BSD local node
1: # is enabled via /Applications/Utilities/Directory Utility.app
1: #
1: # See the DirectoryService(8) man page for additional information about
1: # Open Directory.
1: ##
1: nobody:*:-2:-2:Unprivileged User:/var/empty:/usr/bin/false
1: root:*:0:0:System Administrator:/var/root:/bin/sh
1: daemon:*:1:1:System Services:/var/root:/usr/bin/false
1: _uucp:*:4:4:Unix to Unix Copy Protocol:/var/spool/uucp:/usr/sbin/uucico
1: _lp:*:26:26:Printing Services:/var/spool/cups:/usr/bin/false
2: _postfix:*:27:27:Postfix Mail Server:/var/spool/postfix:/usr/bin/false
2: _mcxalr:*:54:54:MCX AppLaunch:/var/empty:/usr/bin/false
2: _pcastagent:*:55:55:Podcast Producer Agent:/var/pcast/agent:/usr/bin/false
2: _pcastserver:*:56:56:Podcast Producer Server:/var/pcast/server:/usr/bin/false
2: _serialnumberd:*:58:58:Serial Number Daemon:/var/empty:/usr/bin/false
2: _devdocs:*:59:59:Developer Documentation:/var/empty:/usr/bin/false
2: _sandbox:*:60:60:Seatbelt:/var/empty:/usr/bin/false
2: _mdnsresponder:*:65:65:mDNSResponder:/var/empty:/usr/bin/false
2: _ard:*:67:67:Apple Remote Desktop:/var/empty:/usr/bin/false
2: _www:*:70:70:World Wide Web Server:/Library/WebServer:/usr/bin/false
2: _eppc:*:71:71:Apple Events User:/var/empty:/usr/bin/false
2: _cvs:*:72:72:CVS Server:/var/empty:/usr/bin/false
2: _svn:*:73:73:SVN Server:/var/empty:/usr/bin/false
2: _mysql:*:74:74:MySQL Server:/var/empty:/usr/bin/false
2: _sshd:*:75:75:sshd Privilege separation:/var/empty:/usr/bin/false
2: _qtss:*:76:76:QuickTime Streaming Server:/var/empty:/usr/bin/false
2: _cyrus:*:77:6:Cyrus Administrator:/var/imap:/usr/bin/false
2: _mailman:*:78:78:Mailman List Server:/var/empty:/usr/bin/false
2: _appserver:*:79:79:Application Server:/var/empty:/usr/bin/false
2: _clamav:*:82:82:ClamAV Daemon:/var/virusmails:/usr/bin/false
2: _amavisd:*:83:83:AMaViS Daemon:/var/virusmails:/usr/bin/false
2: _jabber:*:84:84:Jabber XMPP Server:/var/empty:/usr/bin/false
2: _xgridcontroller:*:85:85:Xgrid Controller:/var/xgrid/controller:/usr/bin/false
2: _xgridagent:*:86:86:Xgrid Agent:/var/xgrid/agent:/usr/bin/false
2: _appowner:*:87:87:Application Owner:/var/empty:/usr/bin/false
2: _windowserver:*:88:88:WindowServer:/var/empty:/usr/bin/false
2: _spotlight:*:89:89:Spotlight:/var/empty:/usr/bin/false
2: _tokend:*:91:91:Token Daemon:/var/empty:/usr/bin/false
2: _securityagent:*:92:92:SecurityAgent:/var/empty:/usr/bin/false
2: _calendar:*:93:93:Calendar:/var/empty:/usr/bin/false
2: _teamsserver:*:94:94:TeamsServer:/var/teamsserver:/usr/bin/false
2: _update_sharing:*:95:-2:Update Sharing:/var/empty:/usr/bin/false
2: _installer:*:96:-2:Installer:/var/empty:/usr/bin/false
2: _atsserver:*:97:97:ATS Server:/var/empty:/usr/bin/false
2: _unknown:*:99:99:Unknown User:/var/empty:/usr/bin/false
Osiris JL:  jobs
[1]-  Running                 sed 's/^/1: /' < fifo &
[2]+  Done                    sed 's/^/2: /' < fifo
Osiris JL: echo > fifo
1: 
Osiris JL: jobs
[1]+  Done                    sed 's/^/1: /' < fifo
Osiris JL: 

正如您所看到的,两位读者都必须阅读一些数据。任何时候安排哪位读者取决于o / s的心血来潮。请注意,我小心翼翼地使用echo来打印文件的每一行;那些是原子性的原子写作。

如果我在阅读并回显一行之后使用Perl脚本,例如延迟,那么我很可能已经看到更多确定的行为(读取器1中的两行)(读取器2中每1行)。 / p>

perl -n -e 'while(<>){ print "1: $_"; sleep 1; }' < fifo &
perl -n -e 'while(<>){ print "2: $_"; sleep 2; }' < fifo &

在MacOS X 10.5.8(Leopard)上进行的实验 - 但大多数地方都可能类似。

答案 3 :(得分:1)

我想补充上面的解释,写入(和可能的读取,虽然我无法从联机帮助页中确认这一点)到管道是原子级到一定大小(Linux上为4KiB)。因此,假设我们从一个空管道开始,并且写入器将&lt; = 4KiB数据写入管道。这就是我认为发生的事情:

a)作者一次性写入所有数据。在发生这种情况时,没有其他进程有机会读取(或写入)管道。

b)其中一位读者计划进行I / O.

c)所选读者一次性读取管道中的所有数据,稍后将其打印到标准输出。

我认为这可以解释当你只看到一位读者的输出时。尝试用较小的块写,也许每次写后都要睡觉。

当然,其他人已经回答了为什么每个数据只能由进程读取。

答案 4 :(得分:0)

套接字解决方案有效,但是如果服务器崩溃,则变得复杂。为了允许任何进程成为服务器,我在一个临时文件的末尾使用记录锁定,该文件包含对给定文件的位置/长度/数据更改。我使用临时命名管道将附加请求传递给在临时文件末尾具有写锁的任何进程。

相关问题