簡體   English   中英

Pipe 從子進程到 websocket 的無緩沖標准輸出

[英]Pipe unbuffered stdout from subprocess to websocket

您如何 pipe 從子進程到 websocket 的標准輸出而不需要等待換行符? 目前,下面的代碼僅在換行符上發送標准輸出。

為子進程運行的腳本附加的代碼。 output 是否沒有從那里正確沖洗?

發送數據.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的標准輸出會實時發生。

js客戶端:

var ws = new WebSocket('ws://localhost:8765/');

ws.onmessage = function(event) {
  console.log(event.data);
};

我承認這個問題類似於這些:

從子進程中實時捕獲標准輸出

如何-我-獲取-實時-信息-從-a-subprocess-popen-in-python-2-5 返回

在運行時攔截子進程的標准輸出

但是,如果沒有子流程中的換行符,任何解決方案都無法工作。

如果你寫

      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)

rdunbuf.py :(讀取標准輸出無緩沖的示例)

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")

另請注意,如果在生成正常 output 之前生成大量錯誤消息,您的代碼可能會阻塞,因為您首先嘗試讀取所有正常 output,然后才讀取來自 stderr 的數據。

無論是標准輸出還是標准錯誤,您都應該像在任何管道緩沖區獨立阻塞之前一樣讀取子進程產生的任何數據。 You can use select.select() ( https://docs.python.org/3.8/library/select.html#select.select ) in order to decide whether you had to read from stdout, or stderr

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM