检测 reader 何时关闭命名管道 (FIFO)
Detect when reader closes named pipe (FIFO)
有没有什么方法可以让作者知道 reader 已经关闭了命名管道的末端(或退出),没有 写入它?
我需要知道这一点,因为我写入管道的初始数据不同; reader 期望在其余数据到来之前有一个初始的 header。
目前,我在 write()
因 EPIPE
失败时检测到此问题。然后我设置了一个标记 "next time, send the header"。但是,在我写任何东西之前,reader 可能会关闭管道并 re-open 管道。在这种情况下,我永远不会意识到他做了什么,也不会发送他期望的header。
是否有任何类型的异步事件类型的东西可能对这里有帮助?我没有看到发送任何信号。
请注意,我没有包含任何语言标签,因为这个问题应该被考虑language-agnostic。我的代码是 Python,但答案应该适用于 C 或具有系统 call-level 绑定的任何其他语言。
如果您正在使用基于 poll
系统调用的事件循环,您可以使用包含 EPOLLERR
的事件掩码注册管道。在 Python、select.poll
、
import select
fd = open("pipe", "w")
poller = select.poll()
poller.register(fd, select.POLLERR)
poller.poll()
将等到管道关闭。
要对此进行测试,运行 mkfifo pipe
,启动脚本,然后在另一个终端 运行,例如 cat pipe
。只要您退出 cat
进程,脚本就会终止。
奇怪的是,当最后一个 reader 关闭管道时,select
表明管道是可读的:
writer.py
#!/usr/bin/env python
import os
import select
import time
NAME = 'fifo2'
os.mkfifo(NAME)
def select_test(fd, r=True, w=True, x=True):
rset = [fd] if r else []
wset = [fd] if w else []
xset = [fd] if x else []
t0 = time.time()
r,w,x = select.select(rset, wset, xset)
print 'After {0} sec:'.format(time.time() - t0)
if fd in r: print ' {0} is readable'.format(fd)
if fd in w: print ' {0} is writable'.format(fd)
if fd in x: print ' {0} is exceptional'.format(fd)
try:
fd = os.open(NAME, os.O_WRONLY)
print '{0} opened for writing'.format(NAME)
print 'select 1'
select_test(fd)
os.write(fd, 'test')
print 'wrote data'
print 'select 2'
select_test(fd)
print 'select 3 (no write)'
select_test(fd, w=False)
finally:
os.unlink(NAME)
演示:
1 号航站楼:
$ ./pipe_example_simple.py
fifo2 opened for writing
select 1
After 1.59740447998e-05 sec:
3 is writable
wrote data
select 2
After 2.86102294922e-06 sec:
3 is writable
select 3 (no write)
After 2.15910816193 sec:
3 is readable
2 号航站楼:
$ cat fifo2
test
# (wait a sec, then Ctrl+C)
没有这样的机制。通常,根据 UNIX 方式,两端都没有流打开或关闭的信号。这只能通过(相应地)读取或写入它们来检测。
我会说这是错误的设计。当前,您正在尝试让接收者通过打开管道来发出信号,表明它们可以接收。因此,要么以适当的方式实现此信号,要么将 "closing logic" 合并到管道的发送部分。
有没有什么方法可以让作者知道 reader 已经关闭了命名管道的末端(或退出),没有 写入它?
我需要知道这一点,因为我写入管道的初始数据不同; reader 期望在其余数据到来之前有一个初始的 header。
目前,我在 write()
因 EPIPE
失败时检测到此问题。然后我设置了一个标记 "next time, send the header"。但是,在我写任何东西之前,reader 可能会关闭管道并 re-open 管道。在这种情况下,我永远不会意识到他做了什么,也不会发送他期望的header。
是否有任何类型的异步事件类型的东西可能对这里有帮助?我没有看到发送任何信号。
请注意,我没有包含任何语言标签,因为这个问题应该被考虑language-agnostic。我的代码是 Python,但答案应该适用于 C 或具有系统 call-level 绑定的任何其他语言。
如果您正在使用基于 poll
系统调用的事件循环,您可以使用包含 EPOLLERR
的事件掩码注册管道。在 Python、select.poll
、
import select
fd = open("pipe", "w")
poller = select.poll()
poller.register(fd, select.POLLERR)
poller.poll()
将等到管道关闭。
要对此进行测试,运行 mkfifo pipe
,启动脚本,然后在另一个终端 运行,例如 cat pipe
。只要您退出 cat
进程,脚本就会终止。
奇怪的是,当最后一个 reader 关闭管道时,select
表明管道是可读的:
writer.py
#!/usr/bin/env python
import os
import select
import time
NAME = 'fifo2'
os.mkfifo(NAME)
def select_test(fd, r=True, w=True, x=True):
rset = [fd] if r else []
wset = [fd] if w else []
xset = [fd] if x else []
t0 = time.time()
r,w,x = select.select(rset, wset, xset)
print 'After {0} sec:'.format(time.time() - t0)
if fd in r: print ' {0} is readable'.format(fd)
if fd in w: print ' {0} is writable'.format(fd)
if fd in x: print ' {0} is exceptional'.format(fd)
try:
fd = os.open(NAME, os.O_WRONLY)
print '{0} opened for writing'.format(NAME)
print 'select 1'
select_test(fd)
os.write(fd, 'test')
print 'wrote data'
print 'select 2'
select_test(fd)
print 'select 3 (no write)'
select_test(fd, w=False)
finally:
os.unlink(NAME)
演示:
1 号航站楼:
$ ./pipe_example_simple.py
fifo2 opened for writing
select 1
After 1.59740447998e-05 sec:
3 is writable
wrote data
select 2
After 2.86102294922e-06 sec:
3 is writable
select 3 (no write)
After 2.15910816193 sec:
3 is readable
2 号航站楼:
$ cat fifo2
test
# (wait a sec, then Ctrl+C)
没有这样的机制。通常,根据 UNIX 方式,两端都没有流打开或关闭的信号。这只能通过(相应地)读取或写入它们来检测。
我会说这是错误的设计。当前,您正在尝试让接收者通过打开管道来发出信号,表明它们可以接收。因此,要么以适当的方式实现此信号,要么将 "closing logic" 合并到管道的发送部分。