美文网首页
Nodejs spawn 之stdio

Nodejs spawn 之stdio

作者: 黑曼巴yk | 来源:发表于2019-10-15 11:56 被阅读0次

    spawn,exec,execFile和fork关系

    exec 
      │
    execFile         fork
      │               │     
      └─────spawn─────┘          用户层面
               │
    -----------│------------------------
               │
               │                  nodejs内部
               │                   
         spawn(位于lib/internal/child_process.js)
    

    从上图可以看出,在用户层面其他的三个函数都调用了child_process.spwan

    子进程的stdio(标准输入输出)

    1. options.stdio的值是字符串时,有以下几种取值
    • pipe:相当于['pipe', 'pipe', 'pipe'],子进程的stdio和父进程的stdio通过管道进行连接
    • ignore:相当于['ignore','ignore', 'ignore'],子进程的stdio绑定到/dev/null,丢弃数据的输入输出。
    • inherit:继承父进程相关的stdio,等同于[process.stdin,process.stdout,process.sterr]或者[0,1,2],此时子进程的stdio都是绑定在同一个地方。
    1. 当options.stdio值是数组的时候,前三个元素分别代表stdin,stdout,stderr。如果数组的元素大于3,则会在父子进程之间建立额外的通讯通道,他们可能是下面的值.
    • pipe 通过管道进行通讯,管道两端分别连接父子进程,父进程可以通过subprocess.stdin,subprocess.stdout,subprocess.stderr来引用管道的一端。子进程可以通过process.stdin, process.stdout, process.stderr来引用另外一端
    • ipc:额外的通讯通道,通过ipc channel通讯
    • stream:通过nodejs 的stream 对象通讯,对象底层文件描述符代表一个文件。如:socket,tty,本地文件
    • null, undefined,对于前三个元素,他们会设置为pipe,剩下的元素会设置为ignore

    例子

    1. pipe
      绑定到父进程的process.stdio中
    const child_process = require("child_process");
    const script = (function(data) {
      console.log(data);
    }).toString();
    const node = child_process.spawn("node", ["-e", `( ${script}("pipe,只能通过父进程将它输出") )`], {
      stdio: 'pipe'
    });
    node.stdout.on('data', data => {
      console.log(data.toString())
    })
    
    1. inherit
    const child_process = require("child_process");
    const script = (function(data) {
      console.log(data);
    }).toString();
    child_process.spawn("node", ["-e", `( ${script}("inherit,这一般个会写到控制台") )`], {
      stdio: [process.stdin, process.stdout, process.stderr]
      // 和 stdio: 'inherit'相似
    });
    
    1. 绑定文件描述符(fd)
    const child_process = require("child_process");
    const fd = require("fs").openSync("./node.log", "w+");
    const script = (function(data) {
      console.log(data);
    }).toString();
    
    const node = child_process.spawn("node", ["-e", `( ${script}("整数fd,这一般个会写到某个文件") )`], {
      //stdio绑定到文件描述符fd,它代表文件node.log,因此会输出到该文件
      stdio: [process.stdin, fd, fd]
    });
    
    1. 绑定stream
    const child_process = require("child_process");
    const fd = require("fs").openSync("./node.log", "w+");
    const script = (function(data) {
      console.log(data);
    }).toString();
    
    
    const writableStream = require("fs").createWriteStream(null, {
      flags: "a",
      fd,
    });
    child_process.spawn("node", ["-e", `( ${script}("stream,这一般个会写到某个文件") )`], {
      //输出到流所代表的目的地,注意这个流必须要有文件描述符,否则会失败
      //这个例子中它会输出到文件node.log
      stdio: [process.stdin, writableStream, fd]
    });
    
    1. ipc通道
    // parent.js
    const child_process = require("child_process");
    
    const node = child_process.spawn("node",['./child.js'], {
      shell:false,
      stdio: ['inherit', 'inherit', 'inherit','ipc']
    });
    
    node.send({from: 'parent'});
    
    // child.js
    process.on('message', function(m){
      console.log('message from parent: ' + JSON.stringify(m));
    });
    process.send({from: 'child'});
    

    detached 和守护进程

    生成子进程的时候如果传递了detached=true,则使得子进程成为新的sessiongroup的leader

    const child_process = require("child_process");
    const ping = child_process.spawn("ping", ["localhost"], {
        detached:true,
        stdio: 'ignore'
    });
    ping.unref();
    

    需要成为守护进程,必须要做到以下几点

    • 子进程必须和父进程分离,即detached=true
    • 默认情况下父进程会等待已分离的子进程,调用subprocess.unref()来取消等待
    • 子进程的IO和父进程不能联系。使用stdio: 'ignore'

    refer

    https://cnodejs.org/topic/5aa0e25a19b2e3db18959bee

    相关文章

      网友评论

          本文标题:Nodejs spawn 之stdio

          本文链接:https://www.haomeiwen.com/subject/lnmlmctx.html