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

Vmonteco

我们最近在我们的项目上遇到了一个问题,试图将子过程管道作为整个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在进程之间以及通过管道终止了数据块?缓冲(我们怀疑是原因)不能传输全部数据吗?

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


编辑:这也是有关环境的一些信息:

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
草率的意大利面

问题出在您的JavaScript代码中,您可以在这里找到说明

调用process.exit()将迫使进程尽快退出,即使仍有尚未完成的异步操作(包括对process.stdout和的I / O操作)也尚未完成process.stderr

和:

在大多数情况下,实际上没有必要process.exit()显式调用如果事件循环中没有其他待处理的工作,则Node.js进程将自行退出。process.exitCode可以设置属性,以告知进程正常退出时要使用哪个退出代码。

您是process.exit()在调用process.stdout.write()完成之前进行调用的在POSIX上异步写入管道)。这将导致JS进程过早退出,并在写入所有数据之前中断写入。

如果您要设置错误代码,则应照常进行设置process.exitCode = errorCode,并允许事件循环正常结束而无需调用process.exit()

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

使用两个管道在父进程和子进程之间进行通信

来自分类Dev

Unix管道是否仅限在两个进程之间使用?

来自分类Dev

如何在Process.Start中的两个进程之间使用管道

来自分类Dev

使用什么 IPC 机制在两个 Python 进程之间共享 multiprocessing.Queue 中的数据?

来自分类Dev

如何在Python中的两个独立进程之间来回交换数据

来自分类Dev

在Erlang中的两个进程之间交换消息

来自分类Dev

两个进程之间的命名共享内存

来自分类Dev

两个进程之间的命名共享内存

来自分类Dev

如何知道两个进程之间的共享内存?

来自分类Dev

ps aux | 两个相似进程之间的grep

来自分类Dev

在两个进程之间传递消息

来自分类Dev

我可以在C中两个子进程之间使用相同的管道吗?

来自分类Dev

在Node.js中的两个子进程之间进行管道传输?

来自分类Dev

如何在两个线程之间共享数据

来自分类Dev

为什么我的IPV6在存储时会被截断?

来自分类Dev

在两个进程之间共享一个串行端口

来自分类Dev

当多个进程尝试在两个不同文件系统之间转换相同文件时会发生什么?

来自分类Dev

长整数在插入较短的列时会被转换,不会被截断。为什么?公式是什么?

来自分类Dev

子进程之间的管道

来自分类Dev

如何在Guile中的两个流程之间创建管道?

来自分类Dev

在.NET中的两个进程之间传递流对象/文件句柄

来自分类Dev

如何在Linux中的两个进程之间传递映射?

来自分类Dev

如何在两个进程之间使用AIDL发送图像?

来自分类Dev

使用共享内存在两个进程之间传递套接字描述符

来自分类Dev

在Electron中的两个渲染器进程之间进行通信

来自分类Dev

Directx 12:在两个进程之间共享图形内存

来自分类Dev

使用fork在两个进程之间按字符发送字符串char

来自分类Dev

两个派生进程之间的消息队列导致msgsnd的参数无效

来自分类Dev

不同机器上两个进程之间的Python IPC

Related 相关文章

  1. 1

    使用两个管道在父进程和子进程之间进行通信

  2. 2

    Unix管道是否仅限在两个进程之间使用?

  3. 3

    如何在Process.Start中的两个进程之间使用管道

  4. 4

    使用什么 IPC 机制在两个 Python 进程之间共享 multiprocessing.Queue 中的数据?

  5. 5

    如何在Python中的两个独立进程之间来回交换数据

  6. 6

    在Erlang中的两个进程之间交换消息

  7. 7

    两个进程之间的命名共享内存

  8. 8

    两个进程之间的命名共享内存

  9. 9

    如何知道两个进程之间的共享内存?

  10. 10

    ps aux | 两个相似进程之间的grep

  11. 11

    在两个进程之间传递消息

  12. 12

    我可以在C中两个子进程之间使用相同的管道吗?

  13. 13

    在Node.js中的两个子进程之间进行管道传输?

  14. 14

    如何在两个线程之间共享数据

  15. 15

    为什么我的IPV6在存储时会被截断?

  16. 16

    在两个进程之间共享一个串行端口

  17. 17

    当多个进程尝试在两个不同文件系统之间转换相同文件时会发生什么?

  18. 18

    长整数在插入较短的列时会被转换,不会被截断。为什么?公式是什么?

  19. 19

    子进程之间的管道

  20. 20

    如何在Guile中的两个流程之间创建管道?

  21. 21

    在.NET中的两个进程之间传递流对象/文件句柄

  22. 22

    如何在Linux中的两个进程之间传递映射?

  23. 23

    如何在两个进程之间使用AIDL发送图像?

  24. 24

    使用共享内存在两个进程之间传递套接字描述符

  25. 25

    在Electron中的两个渲染器进程之间进行通信

  26. 26

    Directx 12:在两个进程之间共享图形内存

  27. 27

    使用fork在两个进程之间按字符发送字符串char

  28. 28

    两个派生进程之间的消息队列导致msgsnd的参数无效

  29. 29

    不同机器上两个进程之间的Python IPC

热门标签

归档