我经历了一系列不同的linux命名管道客户端/服务器实现,但大多数都使用了读/写的阻塞默认值。
因为我已经使用poll()来检查其他标志,所以通过poll()检查传入的FIFO数据也是个好主意...
在完成所有研究后,我认为在没有编写器打开管道的情况下,在O_RDWR模式下打开管道是防止管道上无限数量的EOF事件的唯一方法。
这样管道的两端都关闭,其他客户端也可以打开可写端。为了回应我会使用单独的管道......
我的问题是,尽管我发现了一些使用O_RDWR标志的示例,但open()联机帮助页将此标志描述为在分配给FIFO时无效。 (http://linux.die.net/man/3/open)
但是如何在没有O_RDWR的情况下在管道上使用poll()?你认为“O_RDWR”是打开管道的合法方式吗?
答案 0 :(得分:34)
首先,一些预赛:
使用O_NONBLOCK
和poll()
是常见做法 - 而不是相反。要成功运作,您需要确保正确处理所有poll()
和read()
返回状态:
read()
返回值0
表示EOF - 另一方已关闭其连接。这与poll()
返回POLLHUP
revent相对应(通常但不是在所有操作系统上)。在尝试POLLHUP
之前,您可能需要检查read()
,但这并非绝对必要,因为read()
保证在写作方关闭后返回0
。 read()
,并且您有O_RDONLY | O_NONBLOCK
,那么您将获得EOF(read()
重复0
),因为您已经我注意到了。但是,如果在调用poll()
之前使用POLLIN
等待read()
事件,它将等待编写者连接,而不是生成EOF。 read()
返回值-1
通常表示错误。但是,如果errno == EAGAIN
,这只是意味着现在没有更多可用数据且您没有阻止,因此如果其他设备需要处理,您可以返回poll()
。如果errno == EINTR
,则read()
在读取任何数据之前被中断,您可以返回poll()
或立即再次致电read()
。现在,对于Linux:
O_RDONLY
在阅读方面打开,则:
open()
将阻止,直到相应的作者打开。poll()
将在数据准备好被读取或发生EOF时提供POLLIN
重新发送。read()
将阻塞,直到读取所请求的字节数,连接关闭(返回0),信号中断,或发生一些致命的IO错误。阻止这种阻止使用poll()
的目的,这就是poll()
几乎总是与O_NONBLOCK
一起使用的原因。您可以使用alarm()
在超时后从read()
唤醒,但这过于复杂。poll()
POLLHUP
次重审,read()
将无限期地返回0
。此时,读者必须关闭其文件句柄并重新打开它。
O_RDONLY | O_NONBLOCK
在阅读方面打开,则:
open()
不会阻止。poll()
将提供POLLIN
重新发送。如果没有作者,poll()
也将被阻止。read()
将返回-1并设置errno == EAGAIN
,如果连接已关闭,它将返回0
( EOF)还是尚未由作家打开。当errno == EAGAIN
时,这意味着它有时间返回poll()
,因为连接已打开,但没有更多数据。当errno == EINTR
时,read()
尚未读取任何字节且被信号中断,因此可以重新启动。poll()
POLLHUP
个重播,read()
将无限期地返回0
。此时,读者必须关闭其文件句柄并重新打开它。
O_RDWR
在阅读方面打开,则:
open()
不会阻止。poll()
将提供POLLIN
revent。但是,对于命名管道,EOF不会导致POLLIN
或POLLHUP
重新发生。read()
将阻塞,直到读取所请求的字节数,信号中断,或发生其他致命的IO错误。对于命名管道,它不会返回errno == EAGAIN
,也不会在EOF上返回0
。它只会坐在那里直到读取所请求的确切字节数,或者直到它收到一个信号(在这种情况下,它将返回到目前为止读取的字节数,或者如果没有字节则返回-1并设置errno == EINTR
到目前为止被阅读了。)O_RDWR | O_NONBLOCK
在阅读方面打开,则:
open()
不会阻止。poll()
将提供POLLIN
revent。但是,EOF不会导致POLLIN
或POLLHUP
在命名管道上发生。read()
将返回-1
并设置errno == EAGAIN
。这是返回poll()
等待更多数据的时间,可能来自其他流。正如您所关注的那样,将O_RDWR
与管道一起使用并非标准,POSIX或其他地方。
然而,由于这个问题似乎经常出现,所以Linux上制作"弹性命名管道的最佳方法是"即使一方关闭,而且POLLHUP
不会导致0
read()
O_RDWR | O_NONBLOCK
,也会使用poll()
。
我在Linux上看到了处理命名管道的三种主要方法:
(便携式。)没有open(pipe, O_RDONLY);
,只有一个管道:
read()
read()
根据需要提供尽可能多的数据,可能会在read() == -1
次调用上循环播放。
errno == EINTR
和read()
,read() == 0
重新开始。poll()
,则关闭连接,并且已收到所有数据。 (Portable。)使用open(pipe, O_RDONLY | O_NONBLOCK);
,并期望管道(甚至是命名管道)只打开一次,一旦它们关闭,必须由读写器重新打开,设置一个新的管道:
poll()
POLLIN
用于read()
个事件,可能同时在多个管道上。 (注意:这可以防止read()
在连接编写器之前获得多个EOF。)read()
根据需要提供尽可能多的数据,可能会在read() == -1
次调用上循环播放。
errno == EAGAIN
和poll()
,请返回read() == -1
步骤。errno == EINTR
和read()
,read() == 0
重新开始。poll()
,连接已关闭,您必须终止或关闭并重新打开管道。(非便携式,特定于Linux。)使用open(pipe, O_RDWR | O_NONBLOCK);
,期望命名管道永不终止,并且可能多次连接和断开连接:
poll()
POLLIN
用于read()
个事件,可能同时在多个管道上。read()
根据需要提供尽可能多的数据,可能会在read() == -1
次调用上循环播放。
errno == EAGAIN
和poll()
,请返回read() == -1
步骤。errno == EINTR
和read()
,read() == 0
重新开始。O_RDWR
出现问题,那么O_RDONLY
就不应该在命名管道上发生,但只能使用poll()
或未命名的管道;它表示一个必须关闭并重新打开的封闭管道。如果在同一个{{1}}事件处理循环中混合使用命名管道和未命名管道,则可能仍需要处理此案例。答案 1 :(得分:1)
根据open(2)手册页,您可以传递O_RDONLY|O_NONBLOCK
或O_WRONLY|O_NONBLOCK
以避免open
系统调用被阻止(您将获得errno == ENXIO
那个案例)
答案 2 :(得分:0)
在读取过程中保持一个打开的 O_WRONLY 文件描述符与 O_RDONLY 一个。这将实现相同的效果,确保 read() 永远不会返回文件结尾并且 poll() 和 select() 将阻塞。
这是 100% POSIX