lib/net.js
Server.prototype.listen = function(...args) {
// ...
if (typeof options.port === 'number' || typeof options.port === 'string') {
// 如果listen方法只传入了端口号,最后会走到这里
listenInCluster(this, null, options.port | 0, 4, backlog, undefined, options.exclusive);
return this;
}
// ...
};
function listenInCluster(server, address, port, addressType, backlog, fd, exclusive, flags) {
if (cluster === undefined) cluster = require('cluster');
if (cluster.isMaster) {
// 如果是主进程则启动一个服务
// 但是主进程没有调用过listen方法,所以没有走这里一步
server._listen2(address, port, addressType, backlog, fd, flags);
return;
}
const serverQuery = {
address: address,
port: port,
addressType: addressType,
fd: fd,
flags,
};
// 子进程获取主进程服务的句柄
cluster._getServer(server, serverQuery, listenOnMasterHandle);
function listenOnMasterHandle(err, handle) {
server._handle = handle; // 重写handle,对listen方法进行了hack
server._listen2(address, port, addressType, backlog, fd, flags);
}
}
看上面代码可以知道,真正启动服务的方法为server._listen2。在_listen2方法中,最终调用的是_handle下的listen方法。
function setupListenHandle(address, port, addressType, backlog, fd, flags) {
// ...
this._handle.onconnection = onconnection;
var err = this._handle.listen(backlog || 511);
// ...
}
Server.prototype._listen2 = setupListenHandle; // legacy alias
那么cluster._getServer方法到底做了什么呢?
搜寻它的源码,首先向master进程发送了一个消息,消息类型为queryServer。
// child.js
cluster._getServer = function(obj, options, cb) {
// ...
const message = {
act: 'queryServer',
index,
data: null,
...options
};
// 发送消息到master进程,消息类型为 queryServer
send(message, (reply, handle) => {
rr(reply, indexesKey, cb); // Round-robin.
});
// ...
};
这里的rr方法,对前面提到的_handle.listen进行了hack,所有子进程的listen其实是不起作用的。
function rr(message, indexesKey, cb) {
if (message.errno)
return cb(message.errno, null);
var key = message.key;
function listen(backlog) { // listen方法直接返回0,不再进行端口监听
return 0;
}
function close() {
send({ act: 'close', key });
}
function getsockname(out) {
return 0;
}
const handle = { close, listen, ref: noop, unref: noop };
handles.set(key, handle); // 根据key将工作进程的 handle 进行缓存
cb(0, handle);
}
// 这里的cb回调就是前面_getServer方法传入的。 参考之前net模块的listen方法
function listenOnMasterHandle(err, handle) {
server._handle = handle; // 重写handle,对listen方法进行了hack
// 该方法调用后,会对handle绑定一个 onconnection 方法,最后会进行调用
server._listen2(address, port, addressType, backlog, fd, flags);
}
内容版权声明:除非注明,否则皆为本站原创文章。
