Node父进程与子进程

子进程

  • 共享内存空间
  • 子进程之间互相通信实现信息交换
  • 子进程之间共享端口,分配请求

基本操作

/**************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())
})

猜你喜欢

转载自blog.csdn.net/w_bu_neng_ku/article/details/80106219