pomelo源码分析(8)--session

来源:互联网 发布:电气专用画图软件 编辑:程序博客网 时间:2024/06/10 07:45

作者:shihuaping0918@163.com,转载请注明作者

pomelo中有session/frontendSession/backendSession/sessionService。名字看起来都有点像,这一篇准备讲session和sessionService。session是对用户连接的一个抽象,它会调用sessionService。sessionService是session的具体实现底层。session只在frontend服务器中存在。如果还有印象的话,应该能记得gate负责接受外部连接,做frontend的负载均衡,将连接分派到不同的frontend上。connector再做路由处理,转到不同的backend服务器上,也就是逻辑服务器。

在分析session.js前要先分析sessionService.js,因为session实际是抽象了sessionService。从底向上更容易理解。

sessionService.js,先看一下Session的定义,Session中有一个id,uid,还有一个frontendId,还有一个socket。id就是sid,uid就是用户id,socket就是连接对应的socket。ftontendId就是frontend服务器id。sid和uid分别是从哪里来的呢?

/** * Session maintains the relationship between client connection and user information. * There is a session associated with each client connection. And it should bind to a * user id after the client passes the identification. * * Session is created in frontend server and should not be accessed in handler. * There is a proxy class called BackendSession in backend servers and FrontendSession  * in frontend servers. */var Session = function(sid, frontendId, socket, service) {  EventEmitter.call(this);  this.id = sid;          // r  this.frontendId = frontendId; // r  this.uid = null;        // r 注意这里,uid初始是null  this.settings = {};  // private  this.__socket__ = socket;  this.__sessionService__ = service;  this.__state__ = ST_INITED;};

sid实际上是socket创建时指定的一个id。sid = socket.id;,它是在connector中生成的,对于sioconnector,有这样一段代码。

var curId = 1;  sio.on('connection', function (socket) {    var siosocket = new SioSocket(curId++, socket); //curId++就是sid    self.emit('connection', siosocket);    siosocket.on('closing', function(reason) {      siosocket.send({route: 'onKick', reason: reason});    });  });

所以这个sid是connector内部维护的,在服务生命周期内自增的一个ID。uid这这个时候是null,没有赋值的。
connector.js

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

connectorService.js

Session.prototype.bind = function(uid) {  this.uid = uid;  this.emit('bind', uid);};

uid是在bind事件发生时出现的。这个bind被调用的时候,把uid给赋进去了。注意是sessionService里的Session.on(‘bind’…)。pomelo把这个session的名字复用了太多次。有点混乱。

为了避免概念上的混乱,下面总结一下,先说明一下session是指对客户端连接的一个抽象,它里面包含uid,sid,socket,以后出现session这单个单词,就是指连接的抽象。pomelo核心中有一个session component,这个session component是对sessionService的抽象。sessionService位于service下,实现session管理的具体工作。session的具体结构是在sessionService中出现的,叫Session。很绕啊,这就是名字取得不好的弊端。

下面再来看一下session component和sessionService之间是什么样的关系。

var SessionService = require('../common/service/sessionService');module.exports = function(app, opts) {  var cmp = new Component(app, opts);  app.set('sessionService', cmp, true);  return cmp;};/** * Session component. Manage sessions. * * @param {Object} app  current application context * @param {Object} opts attach parameters */var Component = function(app, opts) {  opts = opts || {};  this.app = app;  this.service = new SessionService(opts); //创建sessionService //这段话结尾有个(),代表函数调用  var getFun = function(m) {    return (function() {          return function() {            return self.service[m].apply(self.service, arguments); //arguments是随调用变化的          };    })();  };  // proxy the service methods except the lifecycle interfaces of component  var method, self = this;  for(var m in this.service) { //遍历sessionService的成员    if(m !== 'start' && m !== 'stop') { //如果不是start和stop方法      method = this.service[m]; //取出成员      if(typeof method === 'function') { //如果成员是函数        this[m] = getFun(m); //把函数加到自己模块里      }    }  }};Component.prototype.name = '__session__';

根据上面的分析,session component实际上是对sessionService做了一层代理。把sessionService的函数都加载到sesssion component里来了。这个代理的实现,下一篇文章会专门去讲它。

原创粉丝点击