Python选择器,FIFO运行到无限循环



我正在尝试在我的BSD机器上使用kqueue编写一些非阻塞FIFO代码。下面是小型服务器代码:server.py

import os
import selectors
sel = selectors.KqueueSelector()
TMP_PATH="/tmp/myfifo"
def fifo_read(fd, mask):
data = os.read(fd, 8)
print("fd:{} gives:{} n", fd, data)
sel.unregister(fd)
print("unregistered")
def fifo_accept(listen_fd, mask):
print("accepted {}".format(listen_fd))
fd = os.dup(listen_fd)
print("duped to {}".format(fd))
sel.register(fd, selectors.EVENT_READ, fifo_read)
if __name__ == "__main__":
try:
os.unlink(TMP_PATH)
except:
pass
os.mkfifo(TMP_PATH)
listen_fd = os.open(TMP_PATH, os.O_RDONLY, mode=0o600)
sel.register(listen_fd, selectors.EVENT_READ, fifo_accept)
while True:
events = sel.select()
for key, mask in events:
cb = key.data
cb(key.fileobj, mask)
sel.close()

现在,当我运行client.py时:

import os
TMP_PATH="/tmp/myfifo"
fd = os.open(TMP_PATH, os.O_WRONLY, mode=0o600)
res = os.write(fd, b"1234567")
print("sent {}".format(res))

当我运行客户端时,我得到:sent 7

但是在服务器上,它运行到无限循环。现在我明白了为什么会发生无限循环。我实际上尝试模仿在这个 Python Docs 示例中使用selectors的套接字方式。 这是我尝试过的:

  • 我确实在没有复制fd的情况下尝试了代码,但它仍然处于无限循环中。
  • 我尝试在原始listen_fd上调用sel.unregister,但在这种情况下,第二次运行客户端不起作用(这是预期的)。

如果我错过了什么,任何人都可以告诉我吗?

所以我找到了解决这个问题的一个方法。使用套接字,我们在接受时会得到一个新的套接字对象。因此,我们需要通过调用原始fileobjunregister来模仿这种行为,再次open并调用register

固定代码:

import os
import selectors
sel = selectors.KqueueSelector()
try:
os.unlink("./myfifo")
except:
pass
os.mkfifo("./myfifo", 0o600)

def cb(fp):
sel.unregister(fp)
print(f"got {fp.read()}")
fp.close()
fp2 = open("./myfifo", "rb")
sel.register(fp2, selectors.EVENT_READ, cb)
if __name__ == "__main__":
orig_fp = open("./myfifo", "rb")
print("open done")
ev = sel.register(orig_fp, selectors.EVENT_READ, cb)
print(f"registration done for {ev}")
while True:
events = sel.select()
print(events)
for key, mask in events:
key.data(key.fileobj)

最新更新