NodeJS可以感知和控制自身进程的运行环境和状态,也可以创建子进程并与其协同工作,这使得NodeJS可以把多个程序组合在一起共同完成某项工作,并在其中充当胶水和调度器的作用。

  我们已经知道了NodeJS自带的fs模块比较基础,把一个目录里的所有文件和子目录都拷贝到另一个目录里需要写不少代码。另外我们也知道,终端下的cp命令比较好用,一条cp -r source/* target命令就能搞定目录拷贝。那我们首先看看如何使用NodeJS调用终端命令来简化目录拷贝,示例代码如下:

var child_process = require('child_process');
var util = require('util'); function copy(source, target, callback) {
child_process.exec(
util.format('cp -r %s/* %s', source, target), callback);
} copy('a', 'b', function (err) {
// ...
});

  从以上代码中可以看到,子进程是异步运行的,通过回调函数返回执行结果。

一、API

1、process:官方文档: http://nodejs.org/api/process.html

  任何一个进程都有启动进程时使用的命令行参数,有标准输入标准输出,有运行权限,有运行环境和运行状态。

  在NodeJS中,可以通过process对象感知和控制NodeJS自身进程的方方面面。

  另外需要注意的是,process不是内置模块,而是一个全局对象,因此在任何地方都可以直接使用。

2、Child Process:官方文档: http://nodejs.org/api/child_process.html

  使用child_process模块可以创建和控制子进程。

  该模块提供的API中最核心的是.spawn,其余API都是针对特定使用场景对它的进一步封装,算是一种语法糖。

3、Cluster:官方文档: http://nodejs.org/api/cluster.html

  cluster模块是对child_process模块的进一步封装,专用于解决单进程NodeJS Web服务器无法充分利用多核CPU的问题。使用该模块可以简化多进程服务器程序的开发,让每个核上运行一个工作进程,并统一通过主进程监听端口和分发请求。

二、应用场景

1、如何获取命令行参数

  在NodeJS中可以通过process.argv获取命令行参数

  但是比较意外的是,node执行程序路径和主模块文件路径固定占据了argv[0]argv[1]两个位置,而第一个命令行参数从argv[2]开始。为了让argv使用起来更加自然,可以按照以下方式处理。

function main(argv) {
// ...
} main(process.argv.slice());

2、如何退出程序

  通常一个程序做完所有事情后就正常退出了,这时程序的退出状态码为0。或者一个程序运行时发生了异常后就挂了,这时程序的退出状态码不等于0。如果我们在代码中捕获了某个异常,但是觉得程序不应该继续运行下去,需要立即退出,并且需要把退出状态码设置为指定数字,比如1,就可以按照以下方式:

try {
// ...
} catch (err) {
// ...
process.exit();
}

3、如何控制输入输出

  NodeJS程序的标准输入流(stdin)、一个标准输出流(stdout)、一个标准错误流(stderr)分别对应process.stdinprocess.stdoutprocess.stderr,第一个是只读数据流,后边两个是只写数据流,对它们的操作按照对数据流的操作方式即可。例如,console.log可以按照以下方式实现。

function log() {
process.stdout.write(
util.format.apply(util, arguments) + '\n');
}

4、如何降权

  在Linux系统下,我们知道需要使用root权限才能监听1024以下端口。但是一旦完成端口监听后,继续让程序运行在root权限下存在安全隐患,因此最好能把权限降下来。以下是这样一个例子。

http.createServer(callback).listen(, function () {
var env = process.env,
uid = parseInt(env['SUDO_UID'] || process.getuid(), ),
gid = parseInt(env['SUDO_GID'] || process.getgid(), ); process.setgid(gid);
process.setuid(uid);
});

  上例中有几点需要注意:

  1. 如果是通过sudo获取root权限的,运行程序的用户的UID和GID保存在环境变量SUDO_UIDSUDO_GID里边。如果是通过chmod +s方式获取root权限的,运行程序的用户的UID和GID可直接通过process.getuidprocess.getgid方法获取。

  2. process.setuidprocess.setgid方法只接受number类型的参数。

  3. 降权时必须先降GID再降UID,否则顺序反过来的话就没权限更改程序的GID了。

5、如何创建子进程

  以下是一个创建NodeJS子进程的例子。

var child = child_process.spawn('node', [ 'xxx.js' ]);

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);
});

  上例中使用了.spawn(exec, args, options)方法,该方法支持三个参数。第一个参数是执行文件路径,可以是执行文件的相对或绝对路径,也可以是根据PATH环境变量能找到的执行文件名。第二个参数中,数组中的每个成员都按顺序对应一个命令行参数。第三个参数可选,用于配置子进程的执行环境与行为。

  另外,上例中虽然通过子进程对象的.stdout.stderr访问子进程的输出,但通过options.stdio字段的不同配置,可以将子进程的输入输出重定向到任何数据流上,或者让子进程共享父进程的标准输入输出流,或者直接忽略子进程的输入输出。

6、进程间如何通讯

  在Linux系统下,进程之间可以通过信号互相通信。以下是一个例子。

/* parent.js */
var child = child_process.spawn('node', [ 'child.js' ]); child.kill('SIGTERM'); /* child.js */
process.on('SIGTERM', function () {
cleanUp();
process.exit();
});

  在上例中,父进程通过.kill方法向子进程发送SIGTERM信号,子进程监听process对象的SIGTERM事件响应信号不要被.kill方法的名称迷惑了,该方法本质上是用来给进程发送信号的,进程收到信号后具体要做啥,完全取决于信号的种类和进程自身的代码。

  另外,如果父子进程都是NodeJS进程,就可以通过IPC(进程间通讯)双向传递数据。以下是一个例子。

/* parent.js */
var child = child_process.spawn('node', [ 'child.js' ], {
stdio: [ , , , 'ipc' ]
}); child.on('message', function (msg) {
console.log(msg);
}); child.send({ hello: 'hello' }); /* child.js */
process.on('message', function (msg) {
msg.hello = msg.hello.toUpperCase();
process.send(msg);
});

  可以看到,父进程在创建子进程时,在options.stdio字段中通过ipc开启了一条IPC通道,之后就可以监听子进程对象的message事件接收来自子进程的消息,并通过.send方法给子进程发送消息。在子进程这边,可以在process对象上监听message事件接收来自父进程的消息,并通过.send方法向父进程发送消息。数据在传递过程中,会先在发送端使用JSON.stringify方法序列化,再在接收端使用JSON.parse方法反序列化。

7、如何守护子进程

  守护进程一般用于监控工作进程的运行状态,在工作进程不正常退出时重启工作进程,保障工作进程不间断运行。以下是一种实现方式。

/* daemon.js */
function spawn(mainModule) {
var worker = child_process.spawn('node', [ mainModule ]); worker.on('exit', function (code) {
if (code !== ) {
spawn(mainModule);
}
});
} spawn('worker.js');

  可以看到,工作进程非正常退出时,守护进程立即重启工作进程。

nodejs进程管理的更多相关文章

  1. Linux_CentOS下搭建Nodejs 生产环境-以及nodejs进程管理器pm2的使用

    nodejs安装:https://www.cnblogs.com/loaderman/p/11596661.html nodejs 进程管理器 pm2 的使用 PM2 是一款非常优秀的 Node 进程 ...

  2. nodeJS进程管理器pm2

    pm2是一个带有负载均衡功能的Node应用的进程管理器.当你要把你的独立代码利用全部的服务器上的所有CPU,并保证进程永远都活着,0秒的重载, PM2是完美的. PM2是开源的基于Nodejs的进程管 ...

  3. 【nodejs学习】3.进程管理及异步编程

    进程管理 1.调用终端命令实现目录目录拷贝 var child_procress = require('child_procress'); var util = require('util'); fu ...

  4. nodejs项目进程管理器之pm2

    如果用pm2作为nodejs的进程管理器的话,参考以下两篇文章 程序员小卡:http://www.cnblogs.com/chyingp/p/pm2-documentation.html 官方:htt ...

  5. 使用PM2管理nodejs进程分享

    摘要:pm2 是一个带有负载均衡功能的Node应用的进程管理器.本文主要介绍了详解使用PM2管理nodejs进程,小编觉得挺不错的,现在分享给大家,也给大家做个参考.一起跟随小编过来看看吧,希望能帮助 ...

  6. 服务器端配置nodejs环境(使用pm2进程管理运行)

    一.brew安装: 由于Mac没有装ubantu,所以不能用apt-get命令,在本地命令行下Mac安装homebrew替代:  https://brew.sh 二.新开命令窗口,登录root用户,安 ...

  7. 学习使用PM2管理nodejs进程

    在项目中,偶尔对命令会忘记一下,所以在此记录下pm2的常用命令. 1. pm2是什么?pm2 是一个带有负载均衡的Node应用的进程管理器, 它能够管理Node应用,还能够对应用的运行状态进行监控. ...

  8. 使用 PM2 管理nodejs进程

    pm2 是一个带有负载均衡功能的Node应用的进程管理器. 当你要把你的独立代码利用全部的服务器上的所有CPU,并保证进程永远都活着,0秒的重载, PM2是完美的. 它非常适合IaaS结构,但不要把它 ...

  9. electron教程(二): http服务器, ws服务器, 进程管理

    我的electron教程系列 electron教程(一): electron的安装和项目的创建 electron教程(二): http服务器, ws服务器, 进程管理 electron教程(三): 使 ...

随机推荐

  1. Skywalking总结

    步骤四,完善Agent:你会发现,你在skywalking的Web监控页面看到的项目名称并非你原有的项目名称,而是一个默认的—— Your_ApplicationName.这是因为你还没有配置.打开/ ...

  2. VUE方法

    1.$event 变量 $event 变量用于访问原生DOM事件. <!DOCTYPE html> <html lang="zh"> <head> ...

  3. 【计算机组成原理】中央处理器CPU

    一.CPU的功能和基本结构 1.功能 当用计算机解决某个问题是,我们首先必须为他编写程序,程序是一个指令序列,这个序列明确告诉计算机应该执行什么操作,在什么地方找到用来操作的数据,一旦把程序装入内存器 ...

  4. 03、装饰模式(Decorator)

    一.概念: 动态的给一个对象添加一些额外的职责,就增加的功能来说,装饰模式比生成子类更为灵活.[DP] 二.通俗的理解: 装饰模式是利用其中的方法为来对对象进行包装的,这样每个包装对象的事项就和如何使 ...

  5. TCP/UDP协议(二)

    面试问题:Tcp/Udp协议是什么,各有什么异同点,各自的使用场景? Tcp协议(传输控制协议) tcp是面向连接的协议,在收发数据之前,必须与对方建立可靠的连接: 三次握手:简单形象通俗描述: 主机 ...

  6. MVC+Ninject+三层架构+代码生成 -- 总结(六、邏輯層)

    1.邏輯層的方法應該與數據層的方法一一對應.邏輯層返回的結果都是用接口IResult封裝,用於項目轉換時,能減少變化的代碼量. 2.邏輯層都需要繼承 BaseLogic 類 public class ...

  7. window.postMessage()实现跨域消息传递

    window.postMessage() 方法可以安全地实现跨源通信.通常,对于两个不同页面的脚本,只有当执行它们的页面位于具有相同的协议(通常为https), 端口号(443为https的默认值), ...

  8. git tag 常用笔记

    git tag 常用笔记 查看 tag 列出现有 tag git tag 列出 v1.4.2 相关的 tag git tag -l "v1.4.2" 查看指定 tag 的信息 gi ...

  9. contos7自启动django服务

    研究了很多种办法 1.新建一个sh 文件 vi django_autostart.sh 2.编辑文件内容 #!/bin/bash #chkconfig:345 61 61 //此行的345参数表示,在 ...

  10. vim进阶

    输入终端命令:!+命令 sudo保存:w !sudo tee % 显示当前路径::pwd 查看缓冲区::ls 打开缓冲区文件:buffer 2 命令补全:Tab键 :r!date读shell日期到vi ...