Pomelo中session创建和connection连接过程分析

首先,来看pomelo中,那么组建是如何被载入的。在pomelo.js中,看如下代码:

/**
 * Auto-load bundled components with getters.
 */
fs.readdirSync(__dirname + '/components').forEach(function (filename) {
  if (!/\.js$/.test(filename)) {
    return;
  }
  var name = path.basename(filename, '.js');
  var _load = load.bind(null, './components/', name);
  
  Pomelo.components.__defineGetter__(name, _load);
  Pomelo.__defineGetter__(name, _load);
});

这里使用__defineGetter__设置了组件访问方法,当我们使用Pomelo.components.connector时就能够访问到connector组件,它还是借助于_load方法。而load函数如下:

function load(path, name) {
  if (name) {
    return require(path + name);
  }
  return require(path);
}

就是根据路径去require。。。

在connector.js中,在connector start之后

pro.afterStart = function(cb) {
  this.connector.start(cb);
  this.connector.on('connection', hostFilter.bind(this, bindEvents));
};

这里监听了'connection'事件。当发射connection事件时,最终会调用bindEvents函数,在bindEvents函数中,会去创建session,然后为socket绑定一系列的事件。

var bindEvents = function(self, socket) {
  if(self.connection) {
    self.connection.increaseConnectionCount();
    var statisticInfo = self.connection.getStatisticsInfo();
    var curServer = self.app.getCurServer();
    if(statisticInfo.totalConnCount > curServer['max-connections']) {
      logger.warn('the server %s has reached the max connections %s', curServer.id, curServer['max-connections']);
      socket.disconnect();
      return;
    }
  }

  //create session for connection
  var session = getSession(self, socket);
  var closed = false;

  socket.on('disconnect', function() {
    if(closed) {
      return;
    }
    closed = true;
    if(self.connection) {
      self.connection.decreaseConnectionCount(session.uid);
    }
  });

  socket.on('error', function() {
    if(closed) {
      return;
    }
    closed = true;
    if(self.connection) {
      self.connection.decreaseConnectionCount(session.uid);
    }
  });

  // new message
  socket.on('message', function(msg) {
    var dmsg = msg;
    if(self.decode) {
      dmsg = self.decode(msg);
    } else if(self.connector.decode) {
      dmsg = self.connector.decode(msg);
    }
    if(!dmsg) {
      // discard invalid message
      return;
    }

    // use rsa crypto
    if(self.useCrypto) {
      var verified = verifyMessage(self, session, dmsg);
      if(!verified) {
        logger.error('fail to verify the data received from client.');
        return;
      }
    }

    handleMessage(self, session, dmsg);
  }); //on message end
};

创建session代码,比较重要的就是socket这个参数吧,它是怎么创建的呢?

var getSession = function(self, socket) {
  var app = self.app, sid = socket.id;
  var session = self.session.get(sid);
  if(session) {
    return session;
  }

  session = self.session.create(sid, app.getServerId(), socket);
  logger.debug('[%s] getSession session is created with session id: %s', app.getServerId(), sid);

  // bind events for session
  socket.on('disconnect', session.closed.bind(session));
  socket.on('error', session.closed.bind(session));
  session.on('closed', onSessionClose.bind(null, app));
  session.on('bind', function(uid) {
    logger.debug('session on [%s] bind with uid: %s', self.app.serverId, uid);
    // update connection statistics if necessary
    if(self.connection) {
      self.connection.addLoginedUser(uid, {
        loginTime: Date.now(),
        uid: uid,
        address: socket.remoteAddress.ip + ':' + socket.remoteAddress.port
      });
    }
    self.app.event.emit(events.BIND_SESSION, session);
  });

  session.on('unbind', function(uid) {
    if(self.connection) {
      self.connection.removeLoginedUser(uid);
    }
    self.app.event.emit(events.UNBIND_SESSION, session);
  });

  return session;
};

最终是通过了sessionservice的create完成了创建,然后将创建的session保持在sessionservice中。

 

那么在哪里会发射connector组件的connection事件呢?

搜索代码,在hybirdconnector mqttconnector sioconnector udpconnector中都有发射connection事件。

Pomelo中session创建和connection连接过程分析_第1张图片

以hybirdsocket为例,这里面是发射switcher的connection事件则会导致gensocket的调用,进而又发射connector的connection事件。


/**
 * Start connector to listen the specified port
 */
Connector.prototype.start = function(cb) {
  var app = require('../pomelo').app;
  var self = this;

  var gensocket = function(socket) {
    var hybridsocket = new HybridSocket(curId++, socket);
    hybridsocket.on('handshake', self.handshake.handle.bind(self.handshake, hybridsocket));//监听handshake事件,事件响应为绑定到handshake结构体,参数为hybridsocket
    hybridsocket.on('heartbeat', self.heartbeat.handle.bind(self.heartbeat, hybridsocket));//同上,监听heartbeat事件
    hybridsocket.on('disconnect', self.heartbeat.clear.bind(self.heartbeat, hybridsocket.id));//同上,监听disconnect事件
    hybridsocket.on('closing', Kick.handle.bind(null, hybridsocket));
    self.emit('connection', hybridsocket);//触发Connector的connection事件
  };

  if(!this.ssl) {
    this.tcpServer = net.createServer();//这里创建tcpserver,是调用了nodejs的net模块创建的。
    this.switcher = new Switcher(this.tcpServer, self.opts);

    this.connector = app.components.__connector__.connector;
    this.dictionary = app.components.__dictionary__;
    this.protobuf = app.components.__protobuf__;
    this.decodeIO_protobuf = app.components.__decodeIO__protobuf__;

    this.switcher.on('connection', function(socket) {
      gensocket(socket);
    });

    if(!!this.distinctHost) {
      this.tcpServer.listen(this.port, this.host);
    } else {
      this.tcpServer.listen(this.port);
    }
  } else {
    this.tlssocket = new Tlssocket(this.port, this.opts);
    this.tlssocket.on('connection', function(socket) {
      gensocket(socket);
    });
  }
  process.nextTick(cb);
};

查看switcher.js,最终发现了如下代码:

var Switcher = function(server, opts) {
  EventEmitter.call(this);
  this.server = server;
  this.wsprocessor = new WSProcessor();
  this.tcpprocessor = new TCPProcessor(opts.closeMethod);
  this.id = 1;
  this.timers = {};
  this.timeout = opts.timeout || DEFAULT_TIMEOUT;
  this.setNoDelay = opts.setNoDelay;

  this.server.on('connection', this.newSocket.bind(this));//server的connection事件会触发newSocket
  this.wsprocessor.on('connection', this.emit.bind(this, 'connection'));
  this.tcpprocessor.on('connection', this.emit.bind(this, 'connection'));

  this.state = ST_STARTED;
};

就是说发射了wsprocessor或tcpprocessor的connection事件,会导致switch的的'connection'事件发射。

 

创建newSocket代码如下

Switcher.prototype.newSocket = function(socket) {
  if(this.state !== ST_STARTED) {
    return;
  }
  // if set connection timeout
  if(!!this.timeout) {
    var timer = setTimeout(function() {
      logger.warn('connection is timeout without communication, the remote ip is %s && port is %s', socket.remoteAddress, socket.remotePort);
      socket.destroy();
    }, this.timeout * 1000);

    this.timers[this.id] = timer;
    socket.id = this.id++;
  }

  var self = this;
  socket.once('data', function(data) {
    if(!!socket.id) {
      clearTimeout(self.timers[socket.id]);
      delete self.timers[socket.id];
    }
    if(isHttp(data)) {
      processHttp(self, self.wsprocessor, socket, data);
    } else {
      if(!!self.setNoDelay) {
        socket.setNoDelay(true);
      }
      processTcp(self, self.tcpprocessor, socket, data);
    }
  });
};

这里的socket.id从1开始增加,且不难看出:socket.id = sid = session.id

 

看代码和写代码完全是倒着来的,一步一步往上面追。。

总结下,具体流程就是


Pomelo中session创建和connection连接过程分析_第2张图片

你可能感兴趣的:(pomelo)