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); }
内容版权声明:除非注明,否则皆为本站原创文章。