有趣的是,我刚刚发现添加
universal_newlines=True
作为Popen()解决我的问题的最后一个论点。我猜流不喜欢,print()因为它是以二进制模式打开的。添加此标志以文本模式打开流。当我拥有它时,我将发布一个完整的示例,包括交互式通信。
编辑:
哦,现在我找到了更多与此问题相关的资源。
在 Linux 上似乎更容易,因为有 fcntl 包允许使用非阻塞 read() 设置管道。不幸的是,它似乎在 Windows 上不可用 :( 我希望使用 peek() 调用,但令人惊讶的是,它也在管道上阻塞!:(
所以我们要么被线程困住,要么被现代难以阅读的异步/等待风格困住。
基于上面链接的灵感,我已经达到了以下简单的工作 ftp 示例:
#!/usr/bin/python
import time, sys, subprocess, threading, queue
def enqueue_output(out, queue):
for line in iter(out.readline, b''):
queue.put(line)
out.close()
def getOutput(outQueue):
outStr = ''
try:
while True:
outStr+=outQueue.get_nowait()
except queue.Empty:
return outStr
p = subprocess.Popen("ftp.exe", stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True)
outQueue = queue.Queue()
errQueue = queue.Queue()
outThread = threading.Thread(target=enqueue_output, args=(p.stdout, outQueue))
errThread = threading.Thread(target=enqueue_output, args=(p.stderr, errQueue))
outThread.daemon = True
errThread.daemon = True
outThread.start()
errThread.start()
p.stdin.write('status\n')
p.stdin.flush()
time.sleep(0.2)
errors = getOutput(errQueue)
output = getOutput(outQueue)
print("err:" + errors)
print("out:" + output)
time.sleep(2)
p.stdin.write('help\n')
p.stdin.flush()
time.sleep(0.2)
errors = getOutput(errQueue)
output = getOutput(outQueue)
print("err:" + errors)
print("out:" + output)
time.sleep(2)
p.stdin.write('bye\n')
p.stdin.flush()
time.sleep(0.2)
errors = getOutput(errQueue)
output = getOutput(outQueue)
print("err:" + errors)
print("out:" + output)
time.sleep(2)
print('done')
最后一点:当使用它与我自己的 c++ 程序进行通信时,我必须fflush(stdout)在每次输出后发出。甚至换行符也没有帮助这些东西在不冲洗的情况下落入管道。