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

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

send(worker, reply, handle);
});
}

看到这一步,已经很明显,我们知道了多进行端口共享的实现原理

其实端口仅由master进程中的内部TCP服务器监听了一次
因为net.js 模块中会判断当前的进程是master还是Worker进程
如果是Worker进程调用cluster._getServer 去hack原生的listen 方法
所以在child调用的listen方法,是一个return 0 的空方法,所以不会报端口占用错误

那现在问题来了,既然Worker进程是如何获取到master进程监听服务接收到的connect呢?

监听master进程启动的TCP服务器的connection事件
通过轮询挑选出一个worker
向其发送newconn内部消息,消息体中包含了客户端句柄
有了句柄,谁都知道要怎么处理了哈哈


// lib/internal/cluster/round_robin_handle.js

function RoundRobinHandle(key, address, port, addressType, fd) {

this.server = net.createServer(assert.fail);

if (fd >= 0)
this.server.listen({ fd });
else if (port >= 0)
this.server.listen(port, address);
else
this.server.listen(address); // UNIX socket path.

this.server.once('listening', () => {
this.handle = this.server._handle;
// 监听onconnection方法
this.handle.onconnection = (err, handle) => this.distribute(err, handle);
this.server._handle = null;
this.server = null;
});
}

RoundRobinHandle.prototype.add = function (worker, send) {
// ...
};

RoundRobinHandle.prototype.remove = function (worker) {
// ...
};

RoundRobinHandle.prototype.distribute = function (err, handle) {
// 负载均衡地挑选出一个worker
this.handles.push(handle);
const worker = this.free.shift();
if (worker) this.handoff(worker);
};

RoundRobinHandle.prototype.handoff = function (worker) {
const handle = this.handles.shift();
const message = { act: 'newconn', key: this.key };
// 向work进程其发送newconn内部消息和客户端的句柄handle
sendHelper(worker.process, message, handle, (reply) => {
// ...
this.handoff(worker);
});
};

下面让我们看看Worker进程接收到newconn消息后进行了哪些操作


// lib/child.js
function onmessage(message, handle) {
if (message.act === 'newconn')
onconnection(message, handle);
else if (message.act === 'disconnect')
_disconnect.call(worker, true);
}

// Round-robin connection.
// 接收连接,并且处理
function onconnection(message, handle) {
const key = message.key;
const server = handles[key];
const accepted = server !== undefined;

send({ ack: message.seq, accepted });

if (accepted) server.onconnection(0, handle);