Detailed explanation of the sample code for the communication between parent and child processes from the child_process module of Node. js

Source: Internet
Author: User
This article mainly introduces how to learn the communication between parent and child processes from the child_process module of Node. js, which has some reference value. If you are interested, you can refer to it. This article mainly introduces # wiki/1498.html "target =" _ blank "> Node. the child_process module of js is useful for learning the communication between parent and child processes. If you are interested, refer to it.

The child_process module provides the same way as popen (3) to generate a self-process. This function is mainly provided through the child_process.spawn function:

const spawn = require('child_process').spawn; const ls = spawn('ls', ['-lh', '/usr']); ls.stdout.on('data', (data) => {  console.log(`stdout: ${data}`); }); ls.stderr.on('data', (data) => {  console.log(`stderr: ${data}`); }); ls.on('close', (code) => {  console.log(`child process exited with code $[code]`); });

By default, the stdin, stdout, and stderr pipelines between the Node. js process and the sub-process already exist. Generally, this method can transmit data in a non-blocking way. (Note that some programs use line-buffered I/O internally. Because this does not affect Node. js, which means that the data passed to the sub-process may not be consumed immediately ).

The spawn method of chid-process generates self-processes asynchronously, so Node is not blocked. js event loop, however, the child-process.spawnSync method is synchronous and it will block the event loop only until the Generated Process exits or stops.

Child_process.exec: generate a shell client and use shell to execute the program. When the program is completed, it is passed to the callback function as a stdout and stderr.

Child_process.execFile: similar to exec, but it does not immediately generate a shell

Child_process.fork: generate a new Node. js process, execute a specific module to generate an IPC channel, and then transmit data between the parent process and the child process.

Child_process.execSync: Unlike exec, it blocks Node. js event loops. However, child-process

Child_process.execFileSync: Unlike execFile, it blocks Node. js event loops. However, in some special cases, such as automated shell scripts, the synchronization method may be more useful. In most cases, the synchronization method will have an important impact on the performance, because it will block the event loop.

Child_process.spawn (), child_process.fork (), child_process.exec (), and child_process.execFile () are asynchronous APIs. Each method generates a ChildProcess instance, and this object implements Node. the EventEmitter API of js, so the parent process can register a listener function and be called when a specific event of the child process is triggered. Child_process.exec () and child_process.execFile () can specify an optional callback function, which is called when the child process ends.

Run. bat and. cmd on windows:

The differences between child_process.execand child_process.exe cFile may vary with the platform. ExecFile is more efficient on the Unit/Linux/OSX platform because it does not generate shell. On windows,. bat/. cmd cannot be executed without a terminal, so execFile (child_process.spawn cannot be used) is not available ). In the window,. bat/.htm can be used with spawnscripts. At the same time, it is specified that a shellworker program uses child_process.execute to upload a. bat/.htm file to the worker program (child_process.exe c ).

Const spawn = require ('child _ Process '). spawn; const bat = spawn('cmd.exe ', ['/C', 'My. bat ']); // use the shell method to specify a shell option bat. stdout. on ('data', (data) => {console. log (data) ;}); bat. stderr. on ('data', (data) => {console. log (data) ;}); bat. on ('exit ', (code) => {console. log ('child exited with code $ [code] ');});

Alternatively, you can use the following method:

Const exec = require('child_process'cmd.exe c; // generate exec and pass in at the same time. bat file exec ('My. bat ', (err, stdout, stderr) =>{ if (err) {console. error (err); return;} console. log (stdout );});

Child_process.exec (command [, options] [, callback])

The maxBuffer parameter in options indicates the maximum data volume allowed by stdout/stderr. If the data volume exceeds the limit, the sub-process is killed. The default value is 200*1024 bits; the default value of killSignal is "SIGTERM '. The callback function is called when the process ends. The parameters are error, stdout, and stderr. This method returns a ChildProcess object.

const exec = require('child_process').exec; const child = exec('cat *.js bad_file | wc -l',  (error, stdout, stderr) => {   console.log(`stdout: ${stdout}`);   console.log(`stderr: ${stderr}`);   if (error !== null) {    console.log(`exec error: ${error}`);   } });

The above code generates a shell, then uses this shell to execute the command, and caches the results. The error. code attribute in the callback function indicates the exit code of the sub-process, error. signal indicates the signal to end the process, and any non-zero code indicates an error. The default options parameter values are as follows:

{Encoding: 'utf8', timeout: 0, maxBuffer: 200*1024, // The maximum BIT data allowed by stdout and stderr. If the data exceeds her subprocess, killSignal is killed: 'signature', cwd: null, env: null}

If the timeout value is not 0, the parent process sends a signal, which is specified by killSignal. The default value is "SIGTERM" to terminate the child process. If the child process exceeds the time specified by timeout. Note: Unlike the POSIX system, execute does not replace the current thread. Instead, child_process.exe c uses a shell to execute commands.

Child_process.execFile (file [, args] [, options] [, callback])

File indicates the file to be executed. Child_process.execFile () is similar to exec, but this method does not generate a shell. The specified executable file will immediately upload a new thread, because the efficiency is higher than that of child_process.exe c.

const execFile = require('child_process').execFile; const child = execFile('node', ['--version'], (error, stdout, stderr) => {  if (error) {   throw error;  }  console.log(stdout); });

Because no shell is generated, some I/O redirection and file globbing behaviors are not supported.

Child_process.fork (modulePath [, args] [, options])

ModulePath indicates the module to be executed in the Child thread. If the silent parameter in options is set to true, stdin, stdout, and stderr of the child process will be passed to the parent process. If it is set to false, the child process will inherit from the parent process. Execargv1_value: process.exe cArgv. execPath indicates the executable file used to create sub-processes. This fork method is a special usage of child_process.spawn. It is used to generate a subprocess of Node. js and returns a ChildProcess object like spawn. The returned ChildProcess has a built-in transmission channel for data transmission between the child process and the parent process (completed using the send method of ChildProcess ). We must note that the generated Node. js process and the parent process are independent, except for the IPC transmission channel between them. Each process has its own memory and its own V8 engine. As the generation of a sub-process requires additional resource allocation, a large number of sub-processes are not promoted. However, child_process.forkwill generate a Node. js instance using process.exe cPath of the parent path. execPath in options allows you to specify a new path. The new process generated by specifying execPath communicates with the parent process through the file descriptor (the environment variable NODE_CHANNEL_FD of the child process. The input/output on this file descriptor should be a JSON object. Unlike the POSIX System Call fork, child_process.fork does not clone the current process.

Finally, let's take a look at how the sub-process communicates with the parent process:

Server code:

Var http = require ('http'); var cp = require ('child _ Process'); var server = http. createServer (function (req, res) {var child = cp. fork (dirname + '/cal. js'); // each request generates a new child process. on ('message', function (m) {res. end (m. result + '\ n') ;}); // specify the message event var input = parseInt (req. url. substring (1); // similar to postMessage, but the child is completed through the send method instead of the postMessage method. send ({input: input}) ;}; server. listen (0, 8000 );

Sub-Process Code:

Function fib (n) {if (n <2) {return 1 ;}else {return fib (n-2) + fib (n-1 );}} // accept the process parameter passed by send. on ('message', function (m) {// console. log (m); // print {input: 9} process. send ({result: fib (m. input )});});

Child_process.spawn (command [, args] [, options])

The stdio parameter of the options object indicates the stdio configuration of the sub-process; detached indicates that the sub-process runs independently under the parent process, which is related to the platform; if the shell is set to true, the command is executed in the shell. This method generates a new process using the specified command. If the second parameter does not specify args, it is an empty array by default, and the third parameter is the following object by default, this parameter can also be used to specify additional parameters:

{Cwd: undefined, // The working directory that generates this process. By default, it inherits the current working directory env: process. env // this parameter is used to specify the environment variables visible to the new process. The default value is process. env}

Cwd is used to indicate the working directory generated by the sub-process. If it is not specified, it indicates the current working directory. Env is used to specify the environment variables of the new process. The default value is process. env. The following example shows how to use ls-lh/usr to obtain stdout, stderr, and exit code:

const spawn = require('child_process').spawn; const ls = spawn('ls', ['-lh', '/usr']); ls.stdout.on('data', (data) => {  console.log(`stdout: ${data}`); }); ls.stderr.on('data', (data) => {  console.log(`stderr: ${data}`); }); ls.on('close', (code) => {  console.log(`child process exited with code $[code]`); });

The following is a detailed example of running "ps ax | grep ssh:

const spawn = require('child_process').spawn; const ps = spawn('ps', ['ax']); const grep = spawn('grep', ['ssh']); ps.stdout.on('data', (data) => {  grep.stdin.write(data); }); ps.stderr.on('data', (data) => {  console.log(`ps stderr: ${data}`); }); ps.on('close', (code) => {  if (code !== 0) {   console.log(`ps process exited with code $[code]`);  }  grep.stdin.end(); }); grep.stdout.on('data', (data) => {  console.log(`${data}`); }); grep.stderr.on('data', (data) => {  console.log(`grep stderr: ${data}`); }); grep.on('close', (code) => {  if (code !== 0) {   console.log(`grep process exited with code $[code]`);  } });

The following example is used to check the incorrect execution program:

const spawn = require('child_process').spawn; const child = spawn('bad_command'); child.on('error', (err) => {  console.log('Failed to start child process.'); });

Options. detached:

In windows, if this parameter is set to true, the child process will continue to run if the parent process exits, and the child process has its own console window. If the sub-process is set to true, it cannot be set to false. On a non-window platform, if this parameter is set to true, the sub-process will become the leader of the Process combination and session. At this time, the sub-process will continue to execute after the parent process exits, whether the process is detached. See setsid (2 ).

By default, the parent process waits for the detached sub-process and then exits. To prevent a parent process from waiting for a specified child process, you can use child. unref method. This method will allow the parent process to exit independently unless there is an IPC channel between the parent process and the child process. The following is a long-running detach process that directs its output to a file:

Const fs = require ('fs'); const spawn = require ('child _ Process '). spawn; const out = fs. openSync ('. /out. log', 'A'); const err = fs. openSync ('. /out. log', 'A'); const child = spawn ('prg', [], {detached: true, // dependent on the parent process stdio: ['ignore', out, err]}); child. unref (); // allows the parent process to exit independently without waiting for the child process

When the detached option is used to generate a long-term execution process, if the parent process exits, the child process will not continue to execute, unless a stdio configuration is specified (it is not associated with the parent process ). If the stdio of the parent process is inherited, the child process will maintain a relationship with the control terminal.

Options. stdio

This option is used to configure the pipeline between the parent process and the child process. By default, stdin, stdout, and stderr of the child process are directed to the child of the ChildProcess object. stdin, child. stdout, child. stderr stream, which is the same as setting stdio to ['pipe', 'pipe', 'pipe. Stdio can be any of the following strings:

'Pipe': equivalent to ['pipe', 'pipe', 'pipe'], which is the default option.

'Ignore': equivalent to ['ignore', 'ignore', 'ignore']

'Input': equivalent to [process. stdin, process. stdout, process. stderr] or [, 2]

Generally, stdio is an array. Each option corresponds to the fd of the sub-process. Where 0, 1 and 2 correspond to stdin, stdout, and stderr respectively. If more than fds is set, it is used to create an additional pipeline between the parent process and the child process. It can be any of the following values:

'Pipe': Creates a pipeline between the child process and the parent process. The end of the parent process pipeline will exist as ChildProcess. stdio [fd] of the child_process object. The pipeline created by the fds0-2 also exists in ChildProcess. stdin, ChildProcess. stdout, ChildProcess. stderr

'Ipc ': creates an ipc channel to transmit messages or file descriptors between parent and child processes. The ChildProcess object can have at most one IPC stdio file descriptor. You can use this configuration to enable the send method of ChildProcess. If the parent process writes a JSON object to the file descriptor, ChildProcess. the on ("message") event is triggered on the parent process. If the sub-process is Node. js process, the ipc configuration will enable the process of the sub-process. send (), process. disconnect (), process. on ('disconnect'), and process. on ('message') method.

'Ignore': allows the Node. js sub-process to ignore the file descriptor. Because Node. js will always enable the fds0-2 for the child process, set to ignore will cause Node. js to enable/dev/null, and set this value to the child process fd.

'Strem': shares a readable or writable stream with a sub-process, such as file, socket, and pipe. The file descriptor of this stream is the same as the file descriptor fd of the sub-process. Note: The stream must have its own file descriptor.

Positive Integer: indicates the file descriptor opened by the parent process. Like stream objects, this file descriptor is also shared between parent and child processes.
Null/undefined: use the default value. The fds0, 1, and 2 pipelines of stdio are created (stdin, stdout, stderr ). For fd3 or fdn, the default value is 'ignore'

Const spawn = require ('child _ Process '). spawn; // Child will use parent's stdios // use the stdios spawn ('prg', [], {stdio: 'error'}) of the parent process '}); // generate a shared process. stderr sub-process // Spawn child sharing only stderr spawn ('prg', [], {stdio: ['pipe', 'pipe', process. stderr]}); // Open an extra fd = 4, to interact with programs presenting a // startd-style interface. spawn ('prg', [], {stdio: ['pipe', null, 'pipe']});

Note: When an IPC channel is established between the child process and the parent process, the child process is Node. js process. At this time, the sub-process with IPC channel is enabled (using unref) until the sub-process registers a disconnect event processing handle process. on ('disconnect '), this will allow the sub-process to exit normally and will not continue to run because the IPC channel is opened.

Class: ChildProcess

An instance of this class is an EventEmitters used to represent the generated child process. Instances of this class cannot be created directly. You must use child_process.spawn (), child_process.exec (), child_process.execFile (), or child_process.fork () to complete the process.

'Close' event:

The code indicates the exit code when the sub-process exits. The signal indicates that the signal sent by the sub-process is terminated. This event is triggered when the stdio stream of the sub-process is disabled, the difference with the exit event is that multiple processes may share the same stdio streams! (So when a process exits, that is, exit is triggered, close may not be triggered)

'Exit 'event:

The code indicates the exit code when the sub-process exits; the signal indicates that the signal sent by the sub-process stops. This event is triggered when the sub-process ends. If the process exits, the code indicates the exit code of the process to exit. Otherwise, the exit code is null if the sub-process does not exit. If the process is terminated because it receives a signal, signal is the signal, which is a string and the default value is null.

Note: If the exit event is triggered, the stdio stream of the sub-process may still be enabled; Node. js creates a signal processor for SUGUBT and SIGTERM, and Node. the js process does not stop immediately when it receives the signal. Node. js performs a series of cleanup operations before re-raise handled signal. See waitpid (2)

'Disconnect' event:

It is triggered when the ChildProcess. disconnect () method is called in the child process or parent process. At this time, the message cannot be sent or accepted. This is ChildProcess. connected or false.

'Error' event:

When a process cannot be generated and the process cannot be killed, it will be triggered when a message fails to be sent to the sub-process. Note: When an error occurs, the exit event may or may not be triggered. If you have listened to both the exit and error events, pay attention to whether the event processing function will be called multiple times.

'Message' event:

The message parameter indicates a parsed JSON object or initial value. sendHandle can be a net. Socket or net. Server object or undefined. Triggered when the sub-process calls process. send

Child. connected:

After the disconnect method is called, the value is false. Indicates whether data can be sent and received between the parent process and the child process. If the value is false, data cannot be sent.
Child. disconnect ()

Disable the IPC channel between the sub-process and the parent process. At this time, the sub-process can exit normally if there are no other connections to keep the sub-process active. At this time, the child. connected of the parent process and the process. connected of the child process are set to false. data cannot be transmitted at this time. The disconnect event is triggered when no message is received by the process and is triggered immediately when child. disconnect is called. Note: When the sub-process is a Node. js instance, such as child_process.fork, the process. disconnect method will be called in the sub-process and then close the IPC channel.

Child. kill ([signal])

Messages are sent to sub-processes. If no parameter is specified, the SIGTERM signal is sent. For details, refer to signal (7) to view a series of signals.

const spawn = require('child_process').spawn; const grep = spawn('grep', ['ssh']); grep.on('close', (code, signal) => {  console.log(   `child process terminated due to receipt of signal ${signal}`); }); // Send SIGHUP to process grep.kill('SIGHUP');

An error event is triggered when the ChildProcess object cannot transmit signals. Although an error cannot be reported when sending a signal to an exited sub-process, it may lead to unexpected results. In particular, if this PID has been assigned to another process, this will also lead to unexpected results.

Child. pid:

Returns the PID of the process.

Const spawn = require ('child _ Process '). spawn; const grep = spawn ('grep', ['ssh ']); console. log ('spawned child pid: $ {grep. pid} '); grep. stdin. end (); // use grep. stdin. end

Child. send (message [, sendHandle] [, callback])

When the Parent and child processes have an IPC channel, child. send sends messages to sub-processes when the sub-process is Node. js instance, you can use process. on ('message') event reception

The parent process is:

const cp = require('child_process'); const n = cp.fork(`${dirname}/sub.js`); n.on('message', (m) => {  console.log('PARENT got message:', m); }); n.send({ hello: 'world' });

The sub-process is:

process.on('message', (m) => {  console.log('CHILD got message:', m); }); process.send({ foo: 'bar' });

The child process uses the process. send method to send messages to the parent process. In this example, {cmd: 'node _ foo'} is sent '}. When a message contains a NODE _ prefix in its cmd attribute, it is considered to use the Node. js core (reserved by Node. js ). At this time, the process. on ('message') of the sub-process will not be triggered '). Instead, the process. on ('internalmessage') event is used and consumed internally by Node. js. Generally, this method is not used. SendHandle is used to pass a TCP Server or socket to the sub-process, which is accepted by the second parameter of process. on ('message') callback. Callback is triggered when the message has been sent but the sub-process has not yet received it. This function only has one parameter that is successfully null or an Error object. If no callback is specified and the message cannot send ChildProcess, an error event is triggered. This happens when the sub-process has exited. Child. send returns false. If the parent-child process channel is disabled, or the backlog of untransmitted data exceeds a certain limit, this method returns true. This callback method can be used to implement Flow Control:

The following is an example of sending a Server:

const child = require('child_process').fork('child.js'); // Open up the server object and send the handle. const server = require('net').createServer(); server.on('connection', (socket) => {  socket.end('handled by parent'); }); server.listen(1337, () => {  child.send('server', server); });

The sub-process receives the message:

process.on('message', (m, server) => {  if (m === 'server') {   server.on('connection', (socket) => {    socket.end('handled by child');   });  } });

At this time, the server will share the quilt process with the parent process. Some connections can be processed by the parent process and some quilt processes. In the above example, if dgram is used, you should listen to message events instead of connection, and use server. bind instead of server. listen, but it is only available on UNIX platforms.
The following example shows sending a socket object (two sub-processes are generated to process normal and special priorities ):

The parent process is:

const normal = require('child_process').fork('child.js', ['normal']); const special = require('child_process').fork('child.js', ['special']); // Open up the server and send sockets to child const server = require('net').createServer(); server.on('connection', (socket) => {  // If this is special priority  if (socket.remoteAddress === '74.125.127.100') {   special.send('socket', socket);   return;  }  // This is normal priority  normal.send('socket', socket); }); server.listen(1337);

The sub-process is:

process.on('message', (m, socket) => {  if (m === 'socket') {   socket.end(`Request handled with ${process.argv[2]} priority`);  } });

When a socket is sent to a child process, the parent process cannot track when the socket is destroyed. In this case, the connections attribute becomes null, so we recommend that you do not use. maxConnections. Note: This method is used to serialize messages in JSON. stringify.

Child. stderr:

A stream object is a readable stream that represents the stderr of a sub-process. It is the alias of child. stdio [2]. The two represent the same value. If the sub-process is generated through stdio [2], the value is undefined if it is not set to pipe.

Child. stdin:

A writable Stream object. Note: If the sub-process is waiting to read the input, the sub-process will continue to read the data until the end method is called by the stream to close it. If the sub-process is generated through stdio [0] and the pipe is not set, the value is undefined. Child. stdin is the alias of child. stdio [0], indicating the same value.

Const spawn = require ('child _ Process '). spawn; const grep = spawn ('grep', ['ssh ']); console. log ('spawned child pid: $ {grep. pid} '); grep. stdin. end (); // use grep. stdin. end

Child. stdio:

A sparse array of sub-process pipelines. It is the stdio option of the child_process.spawn () function and the value is set to pipe. Child. stdio [0], child. stdio [1], and child. stdio [2] can also be accessed through child. stdin, child. stdout, and child. stderr. In the following example, only the fd1 (stdout) of the child process is set as the pipe, so only the child of the parent process is allowed. stdio [1] is a stream, and all objects in other arrays are null:

const assert = require('assert'); const fs = require('fs'); const child_process = require('child_process'); const child = child_process.spawn('ls', {   stdio: [    0, // Use parents stdin for child    'pipe', // Pipe child's stdout to parent    fs.openSync('err.out', 'w') // Direct child's stderr to a file   ] }); assert.equal(child.stdio[0], null); assert.equal(child.stdio[0], child.stdin); assert(child.stdout); assert.equal(child.stdio[1], child.stdout); assert.equal(child.stdio[2], null); assert.equal(child.stdio[2], child.stderr);

Child. stdout:

A readable stream represents the stdout of the sub-process. If stdio [1] is set to any number except pipe when a sub-process is generated, the value is undefined. The value is the same as that of child. stdio [1 ].

The above is a detailed description of the sample code for the communication between parent and child processes from the child_process module of Node. js. For more information, see other related articles in the first PHP community!

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.