通过管道将未缓冲的stdout从子流程传输到websocket



如何将stdout从子流程管道传输到websocket而不需要等待换行符?目前,下面的代码只在换行符上发送stdout。

为子流程正在运行的脚本附加的代码。输出是否没有从那里正确冲洗?

send_data.py:

import asyncio
import websockets
import subprocess
import sys
import os
async def foo(websocket, path):
print ("socket open")
await websocket.send("successfully connected")
with subprocess.Popen(['sudo','python3', '-u','inline_print.py'],stdout=subprocess.PIPE, stderr=subprocess.PIPE, bufsize=0, universal_newlines=True) as p:
for line in p.stdout:
line = str(line.rstrip())
await websocket.send(line)
p.stdout.flush()
for line in p.stderr:
line = str(line.rstrip())
await websocket.send(line)
p.stdout.flush()

start_server = websockets.serve(foo, "localhost", 8765)
asyncio.get_event_loop().run_until_complete(start_server)
asyncio.get_event_loop().run_forever()

inline_print.py:

from time import sleep
import sys
loading = 'LOADING...LOADING...LOADING...LOADING...LOADING...'
for i in range(50):
print(loading[i], sep='', end=' ', flush=True)
sleep(0.1)

如果end=' '变为end='n',则来自send_data.py的stdout实时发生。

js客户端:

var ws = new WebSocket('ws://localhost:8765/');
ws.onmessage = function(event) {
console.log(event.data);
};

我承认这个问题与以下类似:

从子流程实时捕获stdout

how-do-i-get-real-time-information-back-from-a-subprocess-ppen-in-python-2-5

拦截stdout-of-a-subprocess-whil-it-is-运行

然而,如果没有来自子流程的换行符,任何解决方案都无法工作。

如果您编写

for line in p.stdout:

然后你(有点(含蓄地说,你想等待一个完整的行

你必须使用read(num_bytes)而不是readline()

下面举一个例子来说明:

sub.py:(示例子流程(

import sys, time
for v in range(20):
print(".", end="")
sys.stdout.flush()
if v % 4 == 0:
print()
if v % 3 != 0:
time.sleep(0.5)

rdunbuff.py:(读取stddout unbuffered的示例(

contextlib, time, subprocess
def unbuffered(proc, stream='stdout'):
stream = getattr(proc, stream)
with contextlib.closing(stream):
while True:
last = stream.read(80) # read up to 80 chars
# stop when end of stream reached
if not last:
if proc.poll() is not None:
break
else:
yield last
# open subprocess without buffering and without universal_newlines=True
proc = subprocess.Popen(["./sub.py"], stdout=subprocess.PIPE, bufsize=0)
for l in unbuffered(proc):
print(l)
print("end")

同样请注意,如果在生成正常输出之前生成大量错误消息,则您的代码可能会阻塞,因为您首先尝试读取所有正常输出,然后再从stderr读取数据。

无论是stdout还是stderr,您都应该像在任何管道缓冲区独立阻塞之前一样读取子进程生成的whataver数据。您可以使用select.select()(https://docs.python.org/3.8/library/select.html#select.select(,以便决定是否必须从stdout或stderr 读取

最新更新