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.jsfunction 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);









