适用于Windows的python os.mkfifo()
简短版本(如果你能回答简短版本,它可以帮我完成任务,其余的主要是为了其他有类似任务的人的利益): 在Windows中的python中,我想创建两个文件对象,附加到同一个文件(它不必是硬盘上的实际文件),一个用于读取,一个用于写入,这样,如果读取端尝试读取,它将永远不会得到EOF(它只会阻塞,直到写入某些内容)。我认为在linux操作系统中,mkfifo()可以完成这项工作,但在Windows中它并不存在。可以做些什么?(我必须使用文件对象) 一些额外的细节: 我有一个python模块(不是我写的),它通过stdin和stdout(使用raw_input()和print)玩特定的游戏。我也有一个Windows可执行文件,通过stdin和stdout玩同样的游戏。我想让他们互相对抗,记录他们所有的交流 以下是我可以编写的代码(没有实现适用于Windows的python os.mkfifo(),python,subprocess,pipe,mkfifo,Python,Subprocess,Pipe,Mkfifo,简短版本(如果你能回答简短版本,它可以帮我完成任务,其余的主要是为了其他有类似任务的人的利益): 在Windows中的python中,我想创建两个文件对象,附加到同一个文件(它不必是硬盘上的实际文件),一个用于读取,一个用于写入,这样,如果读取端尝试读取,它将永远不会得到EOF(它只会阻塞,直到写入某些内容)。我认为在linux操作系统中,mkfifo()可以完成这项工作,但在Windows中它并不存在。可以做些什么?(我必须使用文件对象) 一些额外的细节: 我有一个python模块(不是我写的
get\u fifo()
函数,因为我不知道如何在Windows中实现它):
在Windows上,您正在查看 管道是进程用于通信的共享内存的一部分。创建管道的进程是管道服务器。连接到管道的进程是管道客户端。一个进程将信息写入管道,然后另一个进程从管道读取信息 要使用Windows管道,可以使用或。一个特殊的实用程序模块,提供到win32管道API的接口。它包括
popen[234]()
便利功能的实现
请参阅和类似的SO问题(不特定于管道,但指向有用的信息)。对于跨平台解决方案,我建议在localhost(127.0.0.1)上的套接字上构建类似文件的对象——默认情况下,IDLE就是这样解决与您的问题的。遵循上述两个答案,我不小心碰到了答案。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])
os.pipe()
在Windows上返回匿名管道或命名管道,这是非常轻量级和高效的
TCP套接字(如所建议的)更重:例如,您可以在netstat中看到它们,每个套接字都需要一个端口号,每个对等端口的可用端口数限制为64k(例如,从localhost到localhost的64k)
另一方面,命名管道(在窗口上)受到限制,因为:
- 不能在Windows上安装,因为它们不是套接字
- 没有明显的方法可以通过超时来读取()
- 即使让它们成为非阻塞也很困难
makefile()
将套接字包装在与Python兼容的文件句柄中,这样就可以使用它们。这使它成为一些用例的一个有吸引力的选项,例如从一个线程向另一个线程发送stdout
可以使用自动分配的端口号构造套接字,如下所示(基于):
您是否尝试过删除
get_fifo()
并将pythonmodule
与windows可执行文件直接连接:sys.stdin,sys.stdout=p1.stdout,p1.stdin
。由pythonmodule
编辑的所有print
都写入p1。在这种情况下,stdin
和raw_input()
从p1.stdout
读取。如果由于Python端的缓冲问题而失败;尝试使用无缓冲的stdin/stdout运行脚本:python-u your_script.py
并将bufsize=0
参数添加到Popen
。好主意!当TCP套接字执行相同的操作时,不需要在管道上乱动。。。。为什么python不能将代码复制粘贴到自己的mkfifo函数中呢?
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])
with closing(socket.socket(socket.AF_INET, socket.SOCK_STREAM)) as input_socket:
# Avoid socket exhaustion by setting SO_REUSEADDR <https://stackoverflow.com/a/12362623/648162>:
input_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
# localhost doesn't work if the definition is missing from the hosts file,
# and 127.0.0.1 only works with IPv4 loopback, but socket.gethostname()
# should always work:
input_socket.bind((socket.gethostname(), 0))
random_port_number = input_socket.getsockname()[1]
input_socket.listen(1)
# Do something with input_socket, for example pass it to another thread.
output_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# close() should not strictly be necessary here, but since connect() could fail, it avoids leaking fds
# in that case. "If a file descriptor is given, it is closed when the returned I/O object is closed".
with output_socket:
output_socket.connect((socket.gethostname(), random_port_number))
with input_socket:
while True:
readables, _, _ = select.select([input_socket], [], [input_socket], 1.0)
if len(readables) > 0:
input_conn, addr = self.input_socket.accept()
break
with input_conn:
while True:
readables, _, errored = select.select([input_conn], [], [input_conn], 1.0)
if len(errored) > 0:
print("connection errored, stopping")
break
if len(readables) > 0:
read_data = input_conn.recv(1024)
if len(read_data) == 0:
print("connection closed, stopping")
break
else:
print(f"read data: {read_data!r}")