如何非阻塞地读取命名管道?

22

我创建了一个FIFO,并定期以只读和非阻塞模式从a.py中打开它:

os.mkfifo(cs_cmd_fifo_file, 0777)
io = os.open(fifo, os.O_RDONLY | os.O_NONBLOCK)
buffer = os.read(io, BUFFER_SIZE)

从 b.py 中打开 fifo 以进行写入:

out = open(fifo, 'w')
out.write('sth')

然后a.py会引发一个错误:

buffer = os.read(io, BUFFER_SIZE)

OSError: [Errno 11] Resource temporarily unavailable

有人知道出了什么问题吗?


1
可能是什么条件导致已打开的非阻塞命名管道(fifo)在读取时“不可用”?的重复问题。然而,由于其独特的措辞使其成为我在Google上找到的第一个问题,因此这个问题肯定仍然有用。 - Seanny123
NameError: 名称 'fifo' 未定义,请问您能否修复这个例子? - n611x007
2个回答

17

根据read(2)的man手册:

   EAGAIN or EWOULDBLOCK
          The  file  descriptor  fd refers to a socket and has been marked
          nonblocking   (O_NONBLOCK),   and   the   read   would    block.
          POSIX.1-2001  allows  either error to be returned for this case,
          and does not require these constants to have the same value,  so
          a portable application should check for both possibilities.
因此,您得到的是没有可供阅读的数据。可以这样安全地处理错误:
try:
    buffer = os.read(io, BUFFER_SIZE)
except OSError as err:
    if err.errno == errno.EAGAIN or err.errno == errno.EWOULDBLOCK:
        buffer = None
    else:
        raise  # something else has happened -- better reraise

if buffer is None: 
    # nothing was received -- do something else
else:
    # buffer contains some received data -- do something with it

请确保您已导入errno模块: import errno


尝试运行a.py后,出现以下错误: UnboundLocalError: 在赋值之前引用了本地变量'buffer' - chaonin
@chaonin 我猜测原因是(我之前没有使用缓冲区),并更新了我的示例。希望现在更清楚了。 - Jonas Schäfer
2
io = os.open(fifo, os.O_RDONLY | os.O_NONBLOCK)尝试: buffer = os.read(io, BUFFER_SIZE)except OSError as err:if err.errno == errno.EAGAIN or err.errno == errno.EWOULDBLOCK: pass else: raise errjobs_infile = shlex.split(buffer)os.close(io) - chaonin
有趣的是:EAGAIN 和 EWOULDBLOCK 实际上表示相同的意思。事实上,在某些系统上,它们是相同的值。不过检查两者是一个好主意。 - lxs
1
@lxs,实际上,如果您想要可移植性,就必须这样做,正如read(2)手册建议的那样。这很不方便,在python3.3中,我们将捕获BlockingIOError(http://docs.python.org/3/library/exceptions.html#BlockingIOError),它还告诉我们写入了多少个字符。 - Jonas Schäfer

-2
out = open(fifo, 'w')

谁会帮你关闭它? 用这个替换你的打开+写入:

with open(fifo, 'w') as fp:
    fp.write('sth')

更新: 好的,那就把这个做成:

out = os.open(fifo, os.O_NONBLOCK | os.O_WRONLY)
os.write(out, 'tetet')

1
这并没有回答问题,而且考虑到给出的代码显然是片段式的,也不相关。(-1) - Jonas Schäfer
如果你的编辑是为了回应我的抱怨,那么它并没有做到。 - Jonas Schäfer

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接