【问题标题】:Stdout buffer issue using node child_process使用节点 child_process 的标准输出缓冲区问题
【发布时间】:2014-06-19 05:14:13
【问题描述】:

我正在尝试使用节点 child_process 执行 curl,以从本地网络中的共享文件夹中获取 JSON 文件(大约 220Ko)。但它实际上返回了一个我无法解决的缓冲区问题。 这是我的代码:

var exec = require('child_process').exec;

var execute = function(command, callback){
    exec(command, function(error, stdout, stderr){ callback(error, stdout); });
};

execute("curl http://" + ip + "/file.json", function(err, json, outerr) {
    if(err) throw err;
    console.log(json);
})

这是我得到的错误:

if(err) throw err;
          ^
Error: stdout maxBuffer exceeded.
    at Socket.<anonymous> (child_process.js:678:13)
    at Socket.EventEmitter.emit (events.js:95:17)
    at Socket.<anonymous> (_stream_readable.js:746:14)
    at Socket.EventEmitter.emit (events.js:92:17)
    at emitReadable_ (_stream_readable.js:408:10)
    at emitReadable (_stream_readable.js:404:5)
    at readableAddChunk (_stream_readable.js:165:9)
    at Socket.Readable.push (_stream_readable.js:127:10)
    at Pipe.onread (net.js:526:21)

【问题讨论】:

    标签: javascript node.js


    【解决方案1】:

    在答案中添加一些解释。

    exec 命令在将数据发送到父进程之前对其进行缓冲。它通常适用于产生较小输出的命令。出现上述错误是因为执行命令产生的输出大于最大缓冲区大小。解决上述问题的一种方法是按照 Tim Cooper 的回答指定缓冲区大小。

    var execute = function(command, callback){
    exec(command, {maxBuffer: 1024 * 500}, function(error, stdout, stderr){ 
     callback(error, stdout); });
    };
    

    另一种解决方案是使用 spawn 方法,它通常比 exec 更快,并且它在发送前不缓冲数据。它将数据作为流发送,因此永远不会出现缓冲区大小的问题。 Isampaio使用的代码sn-p。

    var child = process.spawn('<process>', [<arg1>, <arg2>]);
    child.stdout.on('data', function (data) {
     console.log('stdout: ' + data);
    });
    child.stderr.on('data', function (data) {
     console.log('stderr: ' + data);
    });
    child.on('close', function (code) {
     console.log('child process exited with code ' + code);
    });
    

    【讨论】:

      【解决方案2】:

      我遇到了类似的问题,我修复了它从 exec 到 spawn:

      var child = process.spawn('<process>', [<arg1>, <arg2>]);
      
      child.stdout.on('data', function (data) {
        console.log('stdout: ' + data);
      });
      
      child.stderr.on('data', function (data) {
        console.log('stderr: ' + data);
      });
      
      child.on('close', function (code) {
          console.log('child process exited with code ' + code);
      });
      

      【讨论】:

      • 这个答案不一定是最合适的。我认为问题中的控制台输出可能只是一个例子。几乎没有人会获取一个 200KB 的文件来将它扔到控制台。但是,如果 process.exec 用于 CLI 工具之类的东西,那么是的,切换到 spawn 应该是要走的路。
      • 哇... spawn 很酷。它甚至没有使用回调或承诺......只是事件。这对于将标准输出流式传输到控制台可能非常有用。 @Pavel Gatilov,这正是我们正在做的。 FFMpeg 喜欢每秒显示进度...这会对缓冲区造成影响
      • 此事件侦听器模式可以与exec 以完全相同的方式使用,而不是spawn(只是不要在exec 中使用回调)。我更喜欢使用exec,因为它不需要将参数拆分为单独的数组。
      【解决方案3】:

      在使用child_process.exec 时,您需要使用并设置maxBuffer 选项。来自documentation

      maxBuffer 指定 stdout 或 stderr 上允许的最大数据量 - 如果超过此值,则子进程将被终止。

      文档还指出maxBuffer 的默认值为 200KB。

      例如,在以下代码中最大缓冲区大小增加到 500KB:

      var execute = function(command, callback){
          exec(command, {maxBuffer: 1024 * 500}, function(error, stdout, stderr){ callback(error, stdout); });
      };
      

      此外,您可能想了解http.get 以了解它是否能够实现您想要做的事情。

      【讨论】:

      • 这解决了我的问题,谢谢!共享文件夹实际上是在需要摘要身份验证的 webdav 协议下,这就是为什么我使用 curl 可以很容易地处理它 curl --digest http://login:password@" + ip + "/webdav/file.json
      • 这个默认值小得离谱。这是我第二次被这种难以找到的方式咬伤。
      • 默认现在是 1MB @jlh, nodejs.org/api/…
      猜你喜欢
      • 2013-10-27
      • 1970-01-01
      • 2012-07-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-12-12
      相关资源
      最近更新 更多