Windows上的python os.mkfifo()
简短版本(如果你能回答这个简短版本,那就足够了,其余的主要是为了帮助其他有类似任务的人):
在Windows的Python中,我想创建两个文件对象,它们连接到同一个文件(不一定是硬盘上的实际文件),一个用于读取,一个用于写入。这样,如果读取端尝试读取,就永远不会遇到文件结束(EOF),它会一直阻塞,直到有东西被写入。我觉得在Linux中可以用os.mkfifo()来实现,但在Windows中没有这个功能。那我该怎么办呢?(我必须使用文件对象)。
一些额外的细节:我有一个Python模块(不是我写的),它通过标准输入和标准输出(使用raw_input()和print)来玩一个特定的游戏。我还有一个Windows可执行文件,也通过标准输入和标准输出来玩同样的游戏。我想让它们互相对战,并记录下它们的所有交流。
这是我能写的代码(get_fifo()
函数没有实现,因为我不知道在Windows上该怎么做):
class Pusher(Thread):
def __init__(self, source, dest, p1, name):
Thread.__init__(self)
self.source = source
self.dest = dest
self.name = name
self.p1 = p1
def run(self):
while (self.p1.poll()==None) and\
(not self.source.closed) and (not self.source.closed):
line = self.source.readline()
logging.info('%s: %s' % (self.name, line[:-1]))
self.dest.write(line)
self.dest.flush()
exe_to_pythonmodule_reader, exe_to_pythonmodule_writer =\
get_fifo()
pythonmodule_to_exe_reader, pythonmodule_to_exe_writer =\
get_fifo()
p1 = subprocess.Popen(exe, shell=False, stdin=subprocess.PIPE, stdout=subprocess.PIPE)
old_stdin = sys.stdin
old_stdout = sys.stdout
sys.stdin = exe_to_pythonmodule_reader
sys.stdout = pythonmodule_to_exe_writer
push1 = Pusher(p1.stdout, exe_to_pythonmodule_writer, p1, '1')
push2 = Pusher(pythonmodule_to_exe_reader, p1.stdin, p1, '2')
push1.start()
push2.start()
ret = pythonmodule.play()
sys.stdin = old_stdin
sys.stdout = old_stdout
4 个回答
如果你想要一个跨平台的解决方案,我建议你在本地(127.0.0.1)建立一个基于套接字的文件样对象——这就是IDLE默认的做法,它解决了一个和你遇到的问题很相似的情况。
在Windows系统上,你可以使用命名管道或匿名管道。
管道是一段共享内存,供不同的程序进行交流。创建管道的程序叫做管道服务器,而连接到管道的程序叫做管道客户端。一个程序把信息写入管道,另一个程序则从管道中读取这些信息。
要在Windows上使用管道,你可以使用Python for Windows扩展(pywin32),或者使用Ctypes模块。还有一个特别的工具模块win32pipe,它提供了与win32管道API的接口,并包含了方便使用的popen[234]()
函数的实现。
你可以查看如何在Python中使用win32 API以及类似的StackOverflow问题(虽然不是专门针对管道,但提供了有用的信息)。
根据上面两个回答,我偶然发现了一个答案。os.pipe()可以解决这个问题。谢谢你们的回答。
我把完整的代码发出来,以防其他人也在寻找这个:
import subprocess
from threading import Thread
import time
import sys
import logging
import tempfile
import os
import game_playing_module
class Pusher(Thread):
def __init__(self, source, dest, proc, name):
Thread.__init__(self)
self.source = source
self.dest = dest
self.name = name
self.proc = proc
def run(self):
while (self.proc.poll()==None) and\
(not self.source.closed) and (not self.dest.closed):
line = self.source.readline()
logging.info('%s: %s' % (self.name, line[:-1]))
self.dest.write(line)
self.dest.flush()
def get_reader_writer():
fd_read, fd_write = os.pipe()
return os.fdopen(fd_read, 'r'), os.fdopen(fd_write, 'w')
def connect(exe):
logging.basicConfig(level=logging.DEBUG,\
format='%(message)s',\
filename=LOG_FILE_NAME,
filemode='w')
program_to_grader_reader, program_to_grader_writer =\
get_reader_writer()
grader_to_program_reader, grader_to_program_writer =\
get_reader_writer()
p1 = subprocess.Popen(exe, shell=False, stdin=subprocess.PIPE, stdout=subprocess.PIPE)
old_stdin = sys.stdin
old_stdout = sys.stdout
sys.stdin = program_to_grader_reader
sys.stdout = grader_to_program_writer
push1 = Pusher(p1.stdout, program_to_grader_writer, p1, '1')
push2 = Pusher(grader_to_program_reader, p1.stdin, p1, '2')
push1.start()
push2.start()
game_playing_module.play()
sys.stdin = old_stdin
sys.stdout = old_stdout
fil = file(LOG_FILE, 'r')
data = fil.read()
fil.close()
return data
if __name__=='__main__':
if len(sys.argv) != 2:
print 'Usage: connect.py exe'
print sys.argv
exit()
print sys.argv
print connect(sys.argv[1])