一直觉得没有读过什么node.js的框架,觉得很遗憾。。。好了,从今天开始,读pomelo的源代码。。。
网易开源的游戏服务器框架,看介绍。。应该还不错。。先看看吧。。。
从它给的聊天的例子来开始吧。。。比较简单。。。无非就是web端通过websocket发送数据到服务器,然后服务器再广播给同房间的人就ok了。。。
我们先来看看pomelo发送数据的格式吧,也就是它的encode方法:
//用于将发送的数据编码为pomelo的格式,其中id为客户端提供,用于区别待会消息的确认
//route可以理解为要将数据发送到什么地方去
//msg就是实际要发送的数据,json格式
//前5个int是头部,头部的前4个是id,第5个表示数据表示route的长度,然后剩下的保存要发送的数据
Protocol.encode = function(id,route,msg){
var msgStr = JSON.stringify(msg);
if (route.length>255) { throw new Error('route maxlength is overflow'); }
//强类型数组
var byteArray = new Uint16Array(HEADER + route.length + msgStr.length);
var index = 0;
byteArray[index++] = (id>>24) & 0xFF;
byteArray[index++] = (id>>16) & 0xFF;
byteArray[index++] = (id>>8) & 0xFF;
byteArray[index++] = id & 0xFF;
byteArray[index++] = route.length & 0xFF;
//先把他们穿华为unicode码
for(var i = 0;i<route.length;i++){
byteArray[index++] = route.charCodeAt(i);
}
for (var i = 0; i < msgStr.length; i++) {
byteArray[index++] = msgStr.charCodeAt(i);
}
//将这些unicode码转化为字符串
return bt2Str(byteArray,0,byteArray.length);
};
其实encode的过程还是相对比较简单的吧,分为头部,route和数据3个部分,如图:
这里位的单位是16位的无符号int(新的版本的javascript引入了强类型数组),先将数据全部转化为了unicode码,然后再将数据转化为字符串。。。
接下来来看看pomelo在web端怎么进行操作(pomeloclient.js)。。。先来看看init函数:
pomelo.init = function(params, cb){
pomelo.params = params;
params.debug = true;
var host = params.host;
var host = "121.199.40.246"; //主机地址
var port = params.port; //主机端口
var url = 'ws://' + host;
if(port) {
url += ':' + port;
}
//进行websocket的链接
socket = io.connect(url, {'force new connection': true, reconnect: false});
socket.on('connect', function(){
console.log('[pomeloclient.init] websocket connected!');
if (cb) {
cb(socket);
}
});
socket.on('reconnect', function() {
console.log('reconnect');
});
//如果收到了数据,那么调用processMessage来处理这些数据
socket.on('message', function(data){
if(typeof data === 'string') {
data = JSON.parse(data);
}
if(data instanceof Array) {
processMessageBatch(pomelo, data);
} else {
processMessage(pomelo, data);
}
});
socket.on('error', function(err) {
console.log(err);
});
socket.on('disconnect', function(reason) {
pomelo.emit('disconnect', reason);
});
};
代码很容易就能懂,就是建立websocket的连接,然后设置一些监听函数,这里我把host的ip改成了自己服务器的ip地址,不然的话使用的是127.0.0.1,那么就只能部署在本地了。。。
接下来是比较重要的request功能,也就是用于向pomelo后台发送数据
//用于向pomelo后台发送数据,route是要发送到的地方
//接下来的参数可以是要发送的数据,以及消息确认的回调函数
pomelo.request = function(route) {
if(!route) {
return;
}
var msg = {};
var cb;
arguments = Array.prototype.slice.apply(arguments);
if(arguments.length === 2){
if(typeof arguments[1] === 'function'){
cb = arguments[1];
}else if(typeof arguments[1] === 'object'){
msg = arguments[1];
}
}else if(arguments.length === 3){
msg = arguments[1];
cb = arguments[2];
}
msg = filter(msg,route);
id++; //当前发送的数据的id
callbacks[id] = cb; //当发送的这个数据有返回的时候,用这个回调函数来处理
var sg = Protocol.encode(id,route,msg); //将数据转化为规定的格式
socket.send(sg);
};
这里参数可以有3个,第一个是route,也就是要发送到的地方,后面两个参数是要发送的数据,可以带一个毁掉函数,用于发送的数据收到了后台的确认之后执行。。。看起来像是消息服务器的pub的过程。。。
嗯,接下来来看看web端是如何调用request来发送数据的吧:
//按了回车按钮之后,执行的函数
$("#entry").keypress(function(e) {
var route = "chat.chatHandler.send"; //要发送到的route
var target = $("#usersList").val();
if(e.keyCode != 13 /* Return */ ) return;
var msg = $("#entry").attr("value").replace("\n", "");
if(!util.isBlank(msg)) {
pomelo.request(route, {
rid: rid, //room的id
content: msg,
from: username,
target: target
}, function(data) {
$("#entry").attr("value", ""); // clear the entry field.
if(target != '*' && target != username) {
addMessage(username, target, msg);
$("#chatHistory").show();
}
});
}
});
这里我们可以看到了这个route的值是什么了。。。这种route的方式让我想起来了ruby on rails,直接与后台的文件夹对应起来就好了。。。
貌似后台的route也就是按照这样的方式来组织的吧。。。还算挺方便的。。。
接下来我们来看看后台chatHandler的send方法的定义吧:
handler.send = function(msg, session, next) {
var rid = session.get('rid'); //获取当前的房间的id
var username = session.uid.split('*')[0];
var channelService = this.app.get('channelService');
var param = {
route: 'onChat',
msg: msg.content,
from: username,
target: msg.target
};
channel = channelService.getChannel(rid, false); //用于向当前房间广播的channel
//the target is all users
if(msg.target == '*') {
channel.pushMessage(param);
}
//the target is specific user
else {
var tuid = msg.target + '*' + rid;
var tsid = channel.getMember(tuid)['sid'];
channelService.pushMessageByUids(param, [{
uid: tuid,
sid: tsid
}]);
}
next(null, {
route: msg.route
});
};
msg就是客户端传过来的数据,另外还有session,这个应该是pomelo来维护的吧。。。
好了,这篇文章略微看了看pomelo提供的chat的例子的web端是如何给后台发送数据的。。。下一篇在来看看后台到底是怎么运行的吧。。。。