pomelo 学习零碎记录 3

self.app.rpc.chat.chatRemote.add(session, uid, self.app.get('serverId'), rid, true, cb); 

类似此类方法为rpc调用

首先调用的是同名的代理方法,代理方法比原方法多一个session参数,作为第一个参数传入

代理方法在/game-server/node_modules/pomelo/node_modules/pomelo-rpc/lib/util/proxy.js 的genFunctionProxy内生成, 所以首先调用的是该文件的57行的方法:

function() {

var args = Array.prototype.slice.call(arguments, 0);

proxyCB.call(null, serviceName, methodName, args, attach, invoke);

}

proxyCB在game-server/node_modules/pomelo/node_modules/pomelo-rpc/lib/rpc-client/client.js中,

在proxyCB中:

var routeParam = args.shift();

var cb = args.pop();

弹出args的第一个和最后一个参数,实际为最开始调用

self.app.rpc.chat.chatRemote.add(session, uid, self.app.get('serverId'), rid, true, cb)

的session和cb

 然后把session传入client的route路由方法中,在app.start开始前可以加载自定义的方法,如果有对应服务器类型的自定义路由方法,则执行自定义路由,如果没有加载自定义的路由方法,则执行components/proxy.js中的defaultRoute路由方法,该方法根据session的uid用crc哈希算法计算 再与目标后端服务器数量取模 得出一个后端服务器,最后得到目标服务器的id

 

路由的接口为:
function(session, msg, app, cb)
 
得到服务器id(serverId)后调用 
client.rpcInvoke(serverId, msg, cb) //之前 self.app.rpc.chat.chatRemote.add的参数此时只剩下(uid, self.app.get('serverId'), rid, true)等四个,被保存在msg.args中,cb独立成一个参数
 
pro.rpcInvoke = function(serverId, msg, cb) {
if(this.state !== STATE_STARTED) {
throw new Error('[pomelo-rpc] fail to do rpc invoke for client is not running');
}
this._station.dispatch(serverId, msg, null, cb);
};
 

_station在game-server/node_modules/pomelo/node_modules/pomelo-rpc/lib/rpc-client/mailstations.js中定义实现

在mailstation中,为每一个serverId都创建一个ws-mailbox用来和后端服务器通信(如果没有设置延迟加载) 

由于设置了延迟加载,所以在前端服务器第一次调用mailstation的dispatch方法时才创建目标后端服务器的邮箱,当邮箱还没有创建好之前,所有转发到后端服务器的信息将被缓存到pending中,创建目标邮箱后,先调用邮箱的connect方法,该方法内将建立前端服务器和目标服务器之间的socket连接,建立连接后将所有缓存在pending中的消息发送到后端服务器.

前端服务器消息通过目标后端服务器对应的mailbox的方法dispatch 用socket.send将消息发送 

====================================

凡是定义有port端口的进程都会加载pemolo.remote组件,

该组件会通过/game-server/node_modules/pomelo/node_modules/pomelo-rpc/lib/rpc-server/server.js创建gateway对象-->remote

 gateway通过acceptor(ws-acceptor.js)监听rpc的请求

acceptor接收到的消息,通过其cb(dispatcher.route)进一步处理

所以当rpc请求最终在dispatcher.route分发到目标服务器的指定方法: 

var args = msg.args.slice(0);

args.push(cb);

method.apply(service, args);

上面提到rpc的代理客户端发送消息到服务器时,参数只剩下4个,并储存在msg.args中,这里可以看出,在执行真正的目标方法时,参数又添加了cb,和后端服务器的add方法申明的接口一样了. 

==================================

小结:

客户端: 

self.app.rpc.chat.chatRemote.add(session, uid, self.app.get('serverId'), rid, true, function(users) {

next(null, {

code: 200,

users: users

});

});

服务端: 

ChatRemote.prototype.add = function(uid, sid, name, flag, cb) {

console.log('2');

var channel = this.channelService.getChannel(name, flag);

if( !! channel) {

channel.add(uid, sid);

}

cb(this.get(name, flag));

};  

rpc客户端调用服务器的代理会多一个session参数,代理在正式和后端服务器通讯之前,通过session计算出要连接的后端服务器id,然后连接后端服务器,客户端的cb是rpc调用成功后执行的, 服务端的cb是执行目标方法后执行的,它们的接口一样.所以从宏观上看,代理的add方法的cb是又服务端调用的.

  

服务端的cb是ws-acceptor.js中的 

function() {

var args = Array.prototype.slice.call(arguments, 0);

for(var i=0, l=args.length; i<l; i++) {

if(args[i] instanceof Error) {

args[i] = cloneError(args[i]);

}

}

var resp = {id: pkg.id, resp: Array.prototype.slice.call(args, 0)};

if(acceptor.cacheMsg) {

enqueue(socket, acceptor, resp);

} else {

socket.emit('message', resp);

}

 

可见服务端执行请求后,会通过socket连接把结果回传到客户端的ws-mailbox.js

 

 =======================================

chanelService 保存自定义的频道名,每个频道里保存前端服务器的ID:sid和每个用户的ID:uid在groups,groups[sid]取得所有通过同一个前端服务器登陆的uid 

========================================

客户端也可以直接调用后端服务器的handler,但是内部实际上是先连接到前端服务器,在components/server.js中执行

app.sysrpc[routeRecord.serverType].msgRemote.forwardMessage

通过rpc调用后端服务器的forwardMessage方法(/game-server/node_modules/pomelo/lib/common/remote/backend/msgRemote.js),在forwardMessage方法中重新调用后端服务器的server.handle方法以调用客户端的目标方法.

转载于:https://www.cnblogs.com/andyleeblog/archive/2012/12/08/2809186.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值