【发布时间】:2020-05-01 13:45:23
【问题描述】:
我们最近在我们的项目中遇到了一个问题,同时尝试将一个完整的 base64 编码图片(大约 355K)传输到它的父进程:但图片似乎被随机截断,我们仍然没有得到这种行为,也没有找到解决方案.
我们找到了一种解决方法,通过基于临时文件的通信传输这些图片,但我们仍然想了解这些进程间通信限制的问题。
这是我们成功生成的最接近的最小且可重现的示例,它突出了这种行为,我们有一个 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
【问题讨论】:
标签: node.js python-3.x subprocess pipe ipc