使用文件描述符在进程间通信

0 投票
1 回答
2168 浏览
提问于 2025-04-16 04:27

我有以下的Python代码:

import pty
import subprocess
os=subprocess.os
from subprocess import PIPE
import time
import resource

pipe=subprocess.Popen(["cat"], stdin=PIPE, stdout=PIPE, stderr=PIPE, \
                      close_fds=True)
skip=[f.fileno() for f in (pipe.stdin, pipe.stdout, pipe.stderr)]
pid, child_fd = pty.fork()
if(pid==0):
    max_fd=resource.getrlimit(resource.RLIMIT_NOFILE)[0]
    fd=3
    while fd<max_fd:
        if(fd not in skip):
            try:
                os.close(fd)
            except OSError:
                pass
            fd+=1
        enviroment=os.environ.copy()
        enviroment.update({"FD": str(pipe.stdin.fileno())})
        os.execvpe("zsh", ["-i", "-s"], enviroment)
else:
    os.write(child_fd, "echo a >&$FD\n")
    time.sleep(1)
    print pipe.stdout.read(2)

我该如何重写它,以便不使用 Popencat 呢?我需要一种方法,可以从一个在交互式命令行中运行的shell函数传递数据,而这些数据不会和其他函数创建的数据混在一起(所以我不能使用stdout或stderr)。

1 个回答

1

好的,我想我明白你的问题了,接下来有两种不同的方法可以选择。

如果你真的想在子进程中给shell提供一个已经打开的文件描述符,你可以用 os.pipe() 来替代 Popen() 调用 cat。这样你就能得到一对真正的文件描述符(不是Python的 file 对象)。写入第二个文件描述符的内容可以从第一个文件描述符中读取,这样就替代了你临时拼凑的 cat-管道。(虽然“cat管道”这个说法听起来挺有趣的……)如果你需要一个双向的连接,也可以使用套接字对(socket.socketpair())来实现同样的效果。

另外,你还可以通过使用命名管道(也叫FIFO)来进一步简化你的工作。如果你对这个概念不太熟悉,命名管道是一种在文件系统中存在的单向管道。使用 os.mkfifo() 函数可以在文件系统上创建这个管道。然后你可以在主进程中打开这个管道进行读取,而在你的shell子进程中打开它进行写入或直接输出。这样可以简化你的代码,并且可以使用像 Pexpect 这样的现有库来与shell进行交互。

撰写回答