首先,来看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事件。
以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
看代码和写代码完全是倒着来的,一步一步往上面追。。
总结下,具体流程就是