带有poll()的命名管道上的O_RDWR

Joe*_*izz 9 linux ipc pipe mkfifo

我经历了不同的linux命名管道客户端/服务器实现,但大多数使用读/写的阻塞默认值.

因为我已经使用poll()来检查其他标志,所以通过poll()检查传入的FIFO数据也是个好主意...

经过所有研究后,我认为在O_RDWR模式下打开管道是在没有编写器打开管道时防止管道上无限数量的EOF事件的唯一方法.

这样管道的两端都是关闭的,其他客户端也可以打开可写端.为了回应我会使用单独的管道......

我的问题是,尽管我发现了一些使用O_RDWR标志的示例,但open()联机帮助页将此标志描述为在分配给FIFO时无法使用.(http://linux.die.net/man/3/open)

但是如何在没有O_RDWR的情况下在管道上使用poll()?你认为"O_RDWR"是打开管道的合法方式吗?

lee*_*eek 35

首先,一些预赛:

使用O_NONBLOCKpoll()是常见的做法 - 而不是相反.要成功运行,您需要确保正确处理所有状态poll()read()返回状态:

  • read()0EOF的返回值- 另一方已关闭其连接.这对应于(通常,但不是在所有操作系统上)poll()返回POLLHUPrevent.您可能希望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()POLLIN当数据准备好被读取或发生EOF时,它将提供一个revent.
    • read()将阻塞,直到读取所请求的字节数,连接关闭(返回0),它被信号中断,或发生一些致命的IO错误.这种阻止类型会破坏使用的目的poll(),这就是poll()几乎总是使用的原因O_NONBLOCK.您可以使用a在超时后alarm()唤醒read(),但这太复杂了.
    • 如果作者关闭,那么读者将收到一个poll() POLLHUP重复,然后read()0无限期地返回.此时,读者必须关闭其文件句柄并重新打开它.
  • 如果您在阅读方面打开O_RDONLY | O_NONBLOCK,则:
    • open()不会阻止.
    • poll()POLLIN当数据准备好被读取或发生EOF时,它将提供一个revent.poll()如果没有作者,也会阻止作者可用.
    • 读取所有当前可用数据后,read()将返回-1并设置errno == EAGAIN连接是否仍处于打开状态,0如果连接已关闭(EOF)或尚未由编写器打开,则将返回.何时errno == EAGAIN,这意味着是时候返回poll(),因为连接已打开但没有更多数据.当errno == EINTR,read()还没有读取任何字节并被信号中断时,可以重新启动它.
    • 如果作者关闭,那么读者将收到一个poll() POLLHUP重复,然后read()0无限期地返回.此时,读者必须关闭其文件句柄并重新打开它.
  • (特定于Linux :)如果你在阅读方面打开O_RDWR,那么:
    • open()不会阻止.
    • poll()POLLIN当数据准备好被读取时,它将提供一个revent.但是,对于命名管道,EOF不会导致POLLIN或发生POLLHUP.
    • read()将阻塞,直到读取所请求的字节数,它被信号中断,或发生一些其他致命的IO错误.对于命名管道,它不会返回errno == EAGAIN,甚至也不会返回0EOF.它只会坐在那里直到读取所请求的确切字节数,或直到它收到一个信号(在这种情况下,它将返回到目前为止读取的字节数,或返回-1并设置errno == EINTR如果到目前为止没有读取字节) .
    • 如果编写器关闭,如果另一个编写器打开命名管道,读者将不会失去读取命名管道的能力,但读者也不会收到任何通知.
  • (特定于Linux :)如果你在阅读方面打开O_RDWR | O_NONBLOCK,那么:
    • open()不会阻止.
    • poll()POLLIN当数据准备好被读取时,它将提供一个revent.但是,EOF不会导致POLLIN或拒绝POLLHUP命名管道.
    • 读取所有当前可用数据后,read()将返回-1并设置errno == EAGAIN.这是返回poll()等待更多数据的时间,可能来自其他流.
    • 如果编写器关闭,如果另一个编写器打开命名管道,读者将不会失去读取命名管道的能力.连接是持久的.

正如您所关注的那样,使用O_RDWR管道并非标准,POSIX或其他地方.

然而,由于这个问题似乎来了的时候,在Linux上的最佳途径,使"弹性命名管道"的生存,即使一方关闭,并不会引起POLLHUPrevents中或返回0read(),就是用O_RDWR | O_NONBLOCK.

我在Linux上看到了处理命名管道的三种主要方法:

  1. (便携式.)没有poll(),并有一个管道:

    • open(pipe, O_RDONLY);
    • 主循环:
      • read()尽可能多的数据,可能循环read()调用.
        • 如果read() == -1errno == EINTR,read()一遍又一遍.
        • 如果read() == 0,连接已关闭,并且已收到所有数据.

  2. (便携式.)随着poll()管道,甚至是命名的管道,只打开一次,一旦它们关闭,必须由读写器重新打开,建立一个新的管道:

    • open(pipe, O_RDONLY | O_NONBLOCK);
    • 主循环:
      • poll()对于POLLIN事件,可能同时在多个管道上.(注意:这可以防止read()在编写器连接之前获得多个EOF.)
      • read()尽可能多的数据,可能循环read()调用.
        • 如果read() == -1errno == EAGAIN,请返回poll()步骤.
        • 如果read() == -1errno == EINTR,read()一遍又一遍.
        • 如果read() == 0,连接已关闭,您必须终止,或关闭并重新打开管道.

  3. (非便携式,特定于Linux.)随着poll()并期望命名管道永不终止,并且可能多次连接和断开连接:

    • open(pipe, O_RDWR | O_NONBLOCK);
    • 主循环:
      • poll()对于POLLIN事件,可能同时在多个管道上.
      • read()尽可能多的数据,可能循环read()调用.
        • 如果read() == -1errno == EAGAIN,请返回poll()步骤.
        • 如果read() == -1errno == EINTR,read()一遍又一遍.
        • 如果read() == 0出现问题 - 它不应该发生O_RDWR在命名管道上,而只发生在管道上O_RDONLY或未命名的管道上; 它表示一个必须关闭并重新打开的封闭管道.如果在同一poll()事件处理循环中混合使用命名管道和未命名管道,则可能仍需要处理此情况.