美文网首页
pomelo源码分析(8)--session

pomelo源码分析(8)--session

作者: 天一阁图书管理员 | 来源:发表于2017-08-27 14:46 被阅读827次

    作者: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里来了。这个代理的实现,下一篇文章会专门去讲它。

    相关文章

      网友评论

          本文标题:pomelo源码分析(8)--session

          本文链接:https://www.haomeiwen.com/subject/uwaudxtx.html