Node.Js中实现端口重用原理详解

2020-06-17 06:27:14易采站长站整理

}, options);

message.address = address;

// 发送queryServer消息给master进程,master 在收到这个消息后,会创建一个开始一个server,并且listen
send(message, (reply, handle) => {
rr(reply, indexesKey, cb); // Round-robin.
});

obj.once('listening', () => {
cluster.worker.state = 'listening';
const address = obj.address();
message.act = 'listening';
message.port = address && address.port || options.port;
send(message);
});
};
//...
// Round-robin. Master distributes handles across workers.
function rr(message, indexesKey, cb) {
if (message.errno) return cb(message.errno, null);
var key = message.key;
// 这里hack 了listen方法
// 子进程调用的listen方法,就是这个,直接返回0,所以不会报端口被占用的错误
function listen(backlog) {
return 0;
}
// ...
const handle = { close, listen, ref: noop, unref: noop };
handles[key] = handle;
// 这个cb 函数是net.js 中的listenOnMasterHandle 方法
cb(0, handle);
}
// lib/net.js
/*
function listenOnMasterHandle(err, handle) {
err = checkBindError(err, port, handle);
server._handle = handle;
// _listen2 函数中,调用的handle.listen方法,也就是上面被hack的listen
server._listen2(address, port, addressType, backlog, fd);
}
*/

master进程收到queryServer消息后进行启动服务

如果地址没被监听过,通过RoundRobinHandle监听开启服务
如果地址已经被监听,直接绑定handel到已经监听到服务上,去消费请求


// lib/internal/cluster/master.js
function queryServer(worker, message) {

const args = [
message.address,
message.port,
message.addressType,
message.fd,
message.index
];

const key = args.join(':');
var handle = handles[key];

// 如果地址没被监听过,通过RoundRobinHandle监听开启服务
if (handle === undefined) {
var constructor = RoundRobinHandle;
if (schedulingPolicy !== SCHED_RR ||
message.addressType === 'udp4' ||
message.addressType === 'udp6') {
constructor = SharedHandle;
}

handles[key] = handle = new constructor(key,
address,
message.port,
message.addressType,
message.fd,
message.flags);
}

// 如果地址已经被监听,直接绑定handel到已经监听到服务上,去消费请求
// Set custom server data
handle.add(worker, (errno, reply, handle) => {
reply = util._extend({
errno: errno,
key: key,
ack: message.seq,
data: handles[key].data
}, reply);

if (errno)
delete handles[key]; // Gives other workers a chance to retry.