子进程
- 共享内存空间
- 子进程之间互相通信实现信息交换
- 子进程之间共享端口,分配请求
基本操作
/**************stdin*************/
process.stdin.resume();
process.stdin.on("data", function(chunk) {
process.stdout.write("进程收到数据:" + chunk);
});
/**************process.argv*************/
process.argv.forEach( function(val, index, array) {
console.log(index + ': ' + val);
});
/**************nextTick*************/
function foo() {
console.log("foo");
}
process.nextTick(foo);
console.log('bar');
// 与上面作用一样
setTimeout(foo,0)
console.log('bar');
/**************events*************/
process.on("exit", function() {
console.log("process exits");
})
//异常退出
process.on("uncaughtException", function(err) {
console.log('catch an uncaughtException:'+ err);
})
//process.exit();
/************** Signal events*************/
process.on("SIGINT", function() {
console.log('receive SIGINT signal');
process.exit();
})
使用spawn创建子进程
- chlid_process(command,[args],[options])
- command:运行的命令
- args:传给命令的参数
- options:开启子进程的选项
- 子进程完成IO后自动退出
var child_process = require('child_process');
/************** child_process*************/
var opts = {
stdio:['pipe','pipe',process.stderr]
}
var spawn = child_process.spawn;
var sp1 = spawn('node', ['server.js']);
var sp2 = spawn('node', ['client.js'],{stdout:'ignore'});
sp1.on("exit", function(code, signal) {
if (!code) {
console.log('sp1 exit, signal:' + signal);
} else {
console.log('sp1 exit, signal:' + signal);
}
process.exit();
})
sp2.stdout.on('data', function(data) {
console.log("subProcess2:" + data);
});
sp2.on("close", function(code, signal) {
console.log('sp2 close all stdio');
})
sp2.on("error", function(code, signal) {
console.log('sp2 error');
})
sp2.on("exit", function(code, signal) {
console.log('subProcess2 exits');
console.log('sp2 id:' + sp2.pid);
sp1.kill("SIGTERM");
})
process.on('exit', function() {
console.log('main process exits');
})
- 默认情况下,只有子进程全部退出,父进程才能退出
- 设置options的detached属性为true,使得允许父进程先退出,子进程继续执行IO
- 如果父进程与子进程共享IO,则父进程不允许先退出,主要子进程主动调用unref()方法才行
var child_process = require('child_process');
var fs = require('fs');
var out = fs.openSync("./message.txt",'w');
var sp = child_process.spawn('node', ['write.js'],{
detached:true,
stdio:[null, out, null]
});
sp.unref();
运行这个程序,观察一下有什么情况?父进程退出,但message.txt仍在不断增长
使用fork创建子进程
- fork开启一个专门用于运行Node.js中的某个模块文件的子进程。
child_process.fork(mudulePath, [args], [options])
- mudulePath:nodejs模块
- args:参数
- options:开启子进程的选项,一个对象
- 子进程完成IO后不会自动退出,需要显式调用process.exit()
- 开启至少需要30ms
- 至少10MB内存
- 运行的是Node.js应用程序的一个实例(Node模块)
var cp = require('child_process');
var fs = require('fs');
var opts = {
//父进程与子进程独立IO
//silent:true
//父进程与子进程共享IO
silent:false
}
//子进程对象
var sp1 = cp.fork(__dirname + "/write.js",opts);
var sp2 = cp.fork(__dirname + "/write2.js",{silent:true});
var sp3 = cp.fork(__dirname + "/write3.js",opts);
sp1.on("message", function(msg) {
console.log(msg);
});
sp2.stdout.on("data", function(msg) {
console.log(msg.toString());
});
sp3.on("message", function(msg) {
console.log(msg);
process.exit();
});
//父进程发送消息失败
sp1.on("error", function(err) {
})
//用子进程对象send:在父进程中向子进程发送消息
sp1.send({name:"sp1"});
sp2.send({name:"sp2"});
sp3.send({name:"sp3"});
父进程与子进程共享服务器
父进程
var cp = require('child_process');
var fs = require('fs');
var http = require('http');
var server = http.createServer();
//子进程对象
var sp1 = cp.fork(__dirname + "/write.js");
server.listen(8080, "127.0.0.1", function() {
sp1.send("server", server);
console.log('父进程中服务器已创建');
var httpServer = http.createServer();
httpServer.on("request", function(req, res) {
if(req.url !== "/favicon.ico") {
var sum = 0;
for(var i = 0; i < 500000; i++) {
sum += i;
}
res.write("客户端请求在父进程中被处理");
res.end("sum=" + sum);
}
});
httpServer.listen(server);
})
子进程
var http = require('http');
process.on("message", function(msg, server) {
if(msg == 'server') {
console.log('子进程中服务器已创建');
var httpServer = http.createServer();
httpServer.on("request", function(req, res) {
if(req.url !== "/favicon.ico") {
var sum = 0;
for(var i = 0; i < 500000; i++) {
sum += i;
}
res.write("客户端请求在子进程中被处理");
res.end("sum=" + sum);
}
});
httpServer.listen(server);
}
})
结果(有时会可能都由子进程或者父进程单独处理,建议增加请求次数,才能看到父进程与子进程交替处理)
F:\后台开发\node-server-test>node client.js
响应内容:客户端请求在子进程中被处理
响应内容:sum=124999750000
响应内容:客户端请求在子进程中被处理
响应内容:sum=124999750000
响应内容:客户端请求在子进程中被处理
响应内容:sum=124999750000
响应内容:客户端请求在子进程中被处理
响应内容:sum=124999750000
响应内容:客户端请求在父进程中被处理
响应内容:sum=124999750000
响应内容:客户端请求在父进程中被处理
响应内容:sum=124999750000
响应内容:客户端请求在父进程中被处理
响应内容:sum=124999750000
响应内容:客户端请求在父进程中被处理
响应内容:sum=124999750000
响应内容:客户端请求在父进程中被处理
响应内容:sum=124999750000
响应内容:客户端请求在父进程中被处理
响应内容:sum=124999750000
父进程与子进程共享socket端口对象
父进程
var cp = require('child_process');
var http = require('http');
var server = http.createServer();
//子进程对象
var sp1 = cp.fork(__dirname + "/write.js");
server.listen(8080, "127.0.0.1", function() {
console.log('父进程中服务器已创建');
})
server.on("connection", function(socket) {
if(socket.remoteAddress == '127.0.0.1') {
sp1.send("socket", socket);
return;
}
socket.end("客户端请求被父进程处理")
})
子进程
var http = require('http');
process.on("message", function(msg, socket) {
if(msg === 'socket') {
socket.end("客户端请求被子进程处理");
}
})
客户端
var http = require('http');
var net = require('net');
var client = new net.Socket();
client.setEncoding('utf8');
client.connect(8080, '127.0.0.1');
client.on("data", function(data) {
console.log(data);
})
父进程开启多个子进程
- Node的cluster模块
- 客户端的请求总是先被主进程接收,然后转发给子进程中的服务器。
- 主进程选择空闲的子进程,分配请求给该子进程。
var cluster = require('cluster');
var http = require('http');
//设置子进程的该运行的主模块
//slient为false时与父进程共享标准I/O
var settings = {
exec:"./write.js",
silent:false
}
cluster.setupMaster(settings);
cluster.fork();
settings.exec = "./write2.js";
cluster.setupMaster(settings);
cluster.fork();
settings.exec = "./write3.js";
cluster.setupMaster(settings);
var worker3 = cluster.fork();
console.log('this code phase is in main process');
//fork事件
cluster.on("fork", function(worker) {
console.log('子进程' + worker.id + "被开启");
});
//主进程接收子进程的反馈信息
cluster.on("online", function(worker) {
console.log('已收到子进程' + worker.id + " 反馈信息");
})
//为子进程的work对象注册listening事件
cluster.on("listening", function(worker, address) {
console.log('子进程中的服务器开始监听,地址为:' + address.address + ":" + address.port);
})
/*
//或者
worker3.on("listeing",function(address) {
console.log('子进程中的服务器开始监听,地址为:' +address.adress +":" + address.port)
}
*/
多个子进程运行服务器,监听同一地址
var http = require('http');
console.log('子进程1');
var server = http.createServer();
server.listen(8080, "127.0.0.1", function() {
console.log('子进程中服务器1已创建');
});
server.on('request', function(req, res) {
console.log(req.url);
res.end("hello i'm server No.1");
})
客户端
var http = require('http');
var net = require('net');
var opts = {
host:"localhost",
port:8080,
method:"GET",
path:"/"
}
for(var i=0; i < 20; i++) {
var req = http.request(opts, function(res) {
res.on("data", function(chunk){
console.log(chunk.toString());
})
});
req.end();
}
父进程与子进程通信
var cluster = require('cluster');
var http = require('http');
var settings = {
exec:"./write.js",
silent:false
}
cluster.setupMaster(settings);
var worker = cluster.fork();
console.log('this code phase is in main process');
//fork事件
cluster.on("fork", function(worker) {
console.log('子进程' + worker.id + "被开启");
});
//主进程接收子进程的反馈信息
cluster.on("online", function(worker) {
console.log('已收到子进程' + worker.id + " 反馈信息");
})
//为子进程的worker对象注册listening事件监听
worker.on("listening", function(address) {
console.log('子进程中的服务器开始监听,地址为:' + address.address + ":" + address.port);
})
//使用子进程的worker向子进程发送消息
worker.send("message")
//在主进程中通过worker对象接收来自子进程发送过来的消息
worker.on("message", function(msg) {
console.log('主进程收到消息:' + msg.toString());
})
//强制关闭子进程
//worker.kill()
//worker.destroy()
worker.on("exit", function(code, signal) {
console.log('子进程退出-->错误码:' + code)
})
子进程
var server = http.createServer();
server.listen(8080, "127.0.0.1", function() {
console.log('子进程中服务器1已创建');
});
server.on('request', function(req, res) {
console.log(req.url);
res.end("hello i'm server No.1");
//向主进程发送消息
process.send("i'm subprocess");
});
process.on("message", function(msg) {
console.log('子进程收到消息' + msg.toString())
})