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