为什么两个进程之间的管道数据太大时会被截断?

问题描述 投票:1回答:1

我们最近在我们的项目中遇到了一个问题,试图将子流程管道作为整个base64编码的图片(约355K)传递到其父流程:但是图片似乎被随机截断了,我们仍然没有得到这种行为,也没有找到解决方案。

我们找到了一种解决方法,可以通过基于tempfile的通信来传输这些图片,但是我们仍然想了解有关这些进程间通信限制的问题。

这里是我们成功产生的最接近的最小和可复制示例,突出了此行为,我们有一个python脚本试图从节点子进程中检索数据,该节点子进程会生成要检索的数据。但是父进程能够获取的数据长度似乎以不确定的方式受到限制。

此示例测试请求的数据长度和实际检索的长度之间的相等性。

  • test.py
#!/usr/bin/env python3

import base64
import sys
import json
import subprocess

def test(l, executable):
    process = subprocess.Popen(
        executable,
        stdin=subprocess.PIPE,
        stdout=subprocess.PIPE,
        stderr=subprocess.PIPE,
    )
    stdout, stderr = process.communicate(input=json.dumps(l).encode())
    exit_code = process.returncode

    if exit_code != 0:
        raise RuntimeError("fail  : " + str(stderr))

    result = base64.b64decode(stdout.decode("utf-8"))
    assert len(result) == l, f"{len(result)} != {l}"
    print(f"Success: {len(result)} == {l}")

if __name__ == "__main__":
    l = int(sys.argv[1]) if len(sys.argv) > 1 else 355000
    try:
        test(l, ["./test.js"])
    except AssertionError as e:
        print("fail :", e)
  • test.js
#!/usr/bin/env node

const http = require("http");
const serveHandler = require("serve-handler");
const btoa = require("btoa");

const EXIT_CODE_SUCCESS = 0;
const EXIT_CODE_ERROR = 4;


async function getDataFromStdin() {
    return new Promise((resolve, reject) => {
        let receivedData = '';

        process.stdin.on("data", chunk => {
            receivedData += chunk.toString();
        });

        process.stdin.on("end", () => {
            result = resolve(JSON.parse(receivedData)); 
            return result;
        });
    })
}

async function main(){
    const len  = await getDataFromStdin();
    const base64 = btoa("0".repeat(Number(len)));
    process.stdout.write(base64);    
}

let errorCode = EXIT_CODE_SUCCESS;
main()
    .catch(err => {
        console.error(err);
        errorCode = EXIT_CODE_ERROR;
    }).finally(() => {
        process.exit(errorCode);
    });
  • 输出
vagrant@sc-dev-machine:/home/vagrant $ ./test.py 1
Success: 1 == 1
vagrant@sc-dev-machine:/home/vagrant $ ./test.py 1000
Success: 1000 == 1000
vagrant@sc-dev-machine:/home/vagrant $ ./test.py 30000
Success: 30000 == 30000
vagrant@sc-dev-machine:/home/vagrant $ ./test.py 60000
fail : 49152 != 60000
vagrant@sc-dev-machine:/home/vagrant $ ./test.py 60000
Success: 60000 == 60000
vagrant@sc-dev-machine:/home/vagrant $ ./test.py 120000
fail : 49152 != 120000
vagrant@sc-dev-machine:/home/vagrant $ ./test.py 120000
fail : 98304 != 120000
vagrant@sc-dev-machine:/home/vagrant $ 

我们还尝试了基于subprocess.check_output()的解决方案,但没有更好的结果。

对此的解释是什么? EOF在进程之间以及通过管道终止了数据块?缓冲(我们怀疑是原因)不能传输全部数据吗?

是否存在一种经过验证的方法来通过过程传输数据(例如文件或图片),而没有长度相关的限制?


edit:这里还有一些有关环境的信息:

subprocess.check_output()
node.js python-3.x subprocess pipe ipc
1个回答
0
投票

问题出在您的JavaScript代码中。在对process.stdout.write(base64)的调用完成之前,您正在调用vagrant@sc-dev-machine:/home/vagrant $ uname -a Linux sc-dev-machine 4.15.0-74-generic #84-Ubuntu SMP Thu Dec 19 08:06:28 UTC 2019 x86_64 x86_64 x86_64 GNU/Linux vagrant@sc-dev-machine:/home/vagrant $ python3 --version Python 3.6.8 。这将导致JS进程在写入所有数据之前过早退出。

请参见process.exit(errorCode)https://nodejs.org/api/process.html#process_a_note_on_process_i_o

© www.soinside.com 2019 - 2024. All rights reserved.