linux - 使用poll()在命名管道上使用O_RDWR

标签 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”是打开管道的合法方法吗???

最佳答案

首先,一些预备:

使用O_NONBLOCKpoll()是常见的做法-并非相反。为了成功工作,您需要确保正确处理所有poll()read()返回状态:

  • 的返回值
  • 的意思是EOF-另一端已关闭其连接。 (通常,但不是在所有操作系统上)这对应于read()返回0清除。您可能需要在尝试poll()之前检查POLLHUP,但这不是绝对必要的,因为可以保证POLLHUP在写端关闭后返回read()
  • 如果您在连接作家之前调用read(),并且拥有0,那么您将反复得到EOF(read()返回O_RDONLY | O_NONBLOCK),您已经注意到。但是,如果在调用read()之前使用0等待poll()事件,它将等待编写器连接,而不产生EOF。
  • POLLIN返回值read()通常表示错误。但是,如果使用read(),这仅意味着现在没有更多数据可用,并且您没有阻塞,因此可以返回到-1以防其他设备需要处理。如果是errno == EAGAIN,则poll()在读取任何数据之前已被中断,您可以返回errno == EINTR或直接立即再次调用read()

  • 现在,对于Linux:
  • 如果使用poll()在阅读侧打开,则:
  • read()将阻塞,直到打开了相应的编写器。
  • 当准备好读取数据或发生EOF时,
  • O_RDONLY将提供open()清除。
  • poll()将一直阻塞,直到读取请求的字节数,关闭连接(返回0),被信号中断或出现致命的IO错误为止。这种阻塞性的做法破坏了使用POLLIN的目的,这就是为什么read()几乎总是与poll()一起使用的原因。您可以使用poll()在超时后从O_NONBLOCK中唤醒,但这太复杂了。
  • 如果编写者关闭,则阅读器将收到alarm() read() revent,并且poll()之后将无限期地返回POLLHUP。此时,读取器必须关闭其文件句柄并重新打开它。
  • 如果使用read()在阅读侧打开,则:
  • 0将不会被阻止。
  • 当准备好读取数据或发生EOF时,
  • O_RDONLY | O_NONBLOCK将提供open()清除。 poll()也将阻塞,直到没有可用的编写器为止。
  • 读取所有当前可用的数据后,如果连接仍处于打开状态,则POLLIN将返回-1并设置poll(),或者如果连接已关闭(EOF)或尚未由编写器打开,则read()将返回errno == EAGAIN。当使用0时,这意味着该返回到errno == EAGAIN了,因为该连接已打开,但是没有更多数据了。当poll()时,errno == EINTR尚未读取任何字节并被信号中断,因此可以重新启动它。
  • 如果编写者关闭,则阅读器将收到read() poll()撤销,并且POLLHUP之后将无限期地返回read()。此时,阅读器必须关闭其文件句柄并重新打开它。
  • (特定于Linux :)如果使用0在阅读侧打开,则:
  • O_RDWR将不会被阻止。
  • 当准备好读取数据时,
  • open()将提供poll()清除。但是,对于命名管道,EOF不会导致POLLINPOLLIN撤消。
  • POLLHUP将一直阻塞,直到读取请求的字节数,被信号中断或发生其他严重的IO错误为止。对于命名管道,它将不会返回read(),甚至不会在EOF上返回errno == EAGAIN。它将一直坐在那里,直到读取了请求的确切字节数,或者直到接收到一个信号为止(在这种情况下,它将返回到目前为止已读取的字节数,或者如果没有读取到字节,则返回-1并设置0 )。
  • 如果编写器关闭,则在另一个编写器打开命名管道的情况下,读取器也不会失去稍后读取命名管道的功能,但是读取器也不会收到任何通知。
  • (特定于Linux :)如果使用errno == EINTR在阅读侧打开,则:
  • O_RDWR | O_NONBLOCK不会被阻止。
  • 当准备好读取数据时,
  • open()将提供poll()清除。但是,EOF不会导致命名管道上的POLLINPOLLIN减少。
  • 读取所有当前可用数据后,POLLHUP将返回read()并设置-1。现在是时候返回errno == EAGAIN以等待更多数据(可能来自其他流)的时候了。
  • 如果编写器关闭,则在另一个编写器打开命名管道的情况下,读取器也不会失去稍后读取命名管道的功能。连接是持久的。

  • 如您所知,POSIX或其他地方对管道使用poll()不是标准的。

    但是,由于这个问题似乎经常出现,因此在Linux上使“ flex 命名管道”的最佳方法是使用O_RDWR,即使当一侧关闭时,该管道仍然存在,并且不会导致POLLHUP减少或返回0作为read(), 。

    我看到了在Linux上处理命名管道的三种主要方法:
  • (便携式。)不使用O_RDWR | O_NONBLOCK,并且使用单个管道:
  • poll()
  • 主循环:
  • open(pipe, O_RDONLY);根据需要提供尽可能多的数据,可能会在read()调用上循环。
  • 如果是read()read() == -1,则errno == EINTR再次重新出现。
  • 如果为read(),则连接已关闭,并且已接收所有数据。
  • (可移植。)使用read() == 0,并期望管道(即使是命名管道)仅打开一次,并且一旦关闭,必须由读取器和写入器都重新打开,从而建立新的管道:
  • poll()
  • 主循环:

    用于open(pipe, O_RDONLY | O_NONBLOCK);事件的
  • poll(),可能一次在多个管道上。 (注意:这可以防止POLLIN在连接编写器之前获取多个EOF。)
  • read()根据需要提供尽可能多的数据,可能会在read()调用上循环。
  • 如果是read()read() == -1,请返回errno == EAGAIN步骤。
  • 如果是poll()read() == -1,则errno == EINTR再次重新出现。
  • 如果为read(),则连接已关闭,您必须终止,或者关闭并重新打开管道。
  • (非便携式,特定于Linux。)使用read() == 0,并期望命名管道永远不会终止,并且可以多次连接和断开连接:
  • poll()
  • 主循环:

    用于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事件处理循环中混合了命名管道和未命名管道,则可能仍需要处理这种情况。
  • 关于linux - 使用poll()在命名管道上使用O_RDWR,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15055065/

    相关文章:

    linux - ubuntu中的文件权限

    shell - 创建一个写入多个文件的管道 (tee)

    linux - 用 tar 备份 home 目录

    python - 在 Python 中在相对路径上创建目录并在绝对路径下运行

    c - 如何为每个子进程分配一个新的终端窗口

    android - ContentProvider 与使用 AIDL/Messenger

    mysql - 如何通过管道下载、解压并导入到mysql转储?

    python - 从 python 中的管道读取是不可能的

    linux - 使用 inotify-tools 作为守护进程处理数据

    c - 从 parent 向 child 发送信号