首页 > 解决方案 > 具有 FIFO 的 Python 选择器运行到无限循环

问题描述

我正在尝试在我的 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

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

如果我遗漏了什么,谁能告诉我?

标签: python-3.xselectkqueue

解决方案


所以我找到了解决这个问题的方法。使用套接字,我们在接受时获得一个新的套接字对象。所以我们需要通过调用unregisteroriginal来模拟这种行为fileobjopen然后再次调用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)

推荐阅读