Node.js的进程管理的深入理解(6)

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);
}
      

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:http://www.heiqu.com/242.html