作者:shihuaping0918@163.com奸鬓,轉(zhuǎn)載請(qǐng)注明作者
pomelo中有session/frontendSession/backendSession/sessionService。名字看起來(lái)都有點(diǎn)像,這一篇準(zhǔn)備講session和sessionService。session是對(duì)用戶連接的一個(gè)抽象歌焦,它會(huì)調(diào)用sessionService途事。sessionService是session的具體實(shí)現(xiàn)底層。session只在frontend服務(wù)器中存在雨让。如果還有印象的話,應(yīng)該能記得gate負(fù)責(zé)接受外部連接忿等,做frontend的負(fù)載均衡栖忠,將連接分派到不同的frontend上。connector再做路由處理这弧,轉(zhuǎn)到不同的backend服務(wù)器上娃闲,也就是邏輯服務(wù)器。
在分析session.js前要先分析sessionService.js匾浪,因?yàn)閟ession實(shí)際是抽象了sessionService皇帮。從底向上更容易理解。
sessionService.js蛋辈,先看一下Session的定義属拾,Session中有一個(gè)id将谊,uid,還有一個(gè)frontendId渐白,還有一個(gè)socket尊浓。id就是sid,uid就是用戶id纯衍,socket就是連接對(duì)應(yīng)的socket栋齿。ftontendId就是frontend服務(wù)器id。sid和uid分別是從哪里來(lái)的呢襟诸?
/**
* 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實(shí)際上是socket創(chuàng)建時(shí)指定的一個(gè)id。sid = socket.id;
歌亲,它是在connector中生成的菇用,對(duì)于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});
});
});
所以這個(gè)sid是connector內(nèi)部維護(hù)的惋鸥,在服務(wù)生命周期內(nèi)自增的一個(gè)ID。uid這這個(gè)時(shí)候是null悍缠,沒(méi)有賦值的卦绣。
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事件發(fā)生時(shí)出現(xiàn)的。這個(gè)bind被調(diào)用的時(shí)候飞蚓,把uid給賦進(jìn)去了迎卤。注意是sessionService里的Session.on('bind'...)。pomelo把這個(gè)session的名字復(fù)用了太多次玷坠。有點(diǎn)混亂。
為了避免概念上的混亂劲藐,下面總結(jié)一下八堡,先說(shuō)明一下session是指對(duì)客戶端連接的一個(gè)抽象,它里面包含uid,sid,socket聘芜,以后出現(xiàn)session這單個(gè)單詞兄渺,就是指連接的抽象。pomelo核心中有一個(gè)session component汰现,這個(gè)session component是對(duì)sessionService的抽象挂谍。sessionService位于service下,實(shí)現(xiàn)session管理的具體工作瞎饲。session的具體結(jié)構(gòu)是在sessionService中出現(xiàn)的口叙,叫Session。很繞啊嗅战,這就是名字取得不好的弊端妄田。
下面再來(lái)看一下session component和sessionService之間是什么樣的關(guān)系俺亮。
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); //創(chuàng)建sessionService
//這段話結(jié)尾有個(gè)(),代表函數(shù)調(diào)用
var getFun = function(m) {
return (function() {
return function() {
return self.service[m].apply(self.service, arguments); //arguments是隨調(diào)用變化的
};
})();
};
// 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') { //如果成員是函數(shù)
this[m] = getFun(m); //把函數(shù)加到自己模塊里
}
}
}
};
Component.prototype.name = '__session__';
根據(jù)上面的分析疟呐,session component實(shí)際上是對(duì)sessionService做了一層代理脚曾。把sessionService的函數(shù)都加載到sesssion component里來(lái)了。這個(gè)代理的實(shí)現(xiàn)启具,下一篇文章會(huì)專門(mén)去講它本讥。