Pomelo 新手周计划
2015-12-23 21:25
399 查看
Pomelo 新手周计划(三)
Pomelo 新手周计划(三) 请大牛帮忙,万分感谢
##前言##今天,我们谈谈Pomelo的会话机制
##会话机制##从pomelo 的api 文档我们可以发现,有三个大类与session有关
LocalSessionService
SessionService
LocalSession
###Session 介绍###从pomelo 的api文档中我们可以总结出:
SessionService 是只存在于前端服务器(frontend),session 以每个客户端请求自增1的形式生成 ,用于管理连接 pomelo的客户端,如果在前端服务器不进行相关控制对于每个请求都会产生一个Session,就是说客户端都会在前端的服务器(frontend)里的sessionService产生一个会话,值得注意的是自pomelo0.4.x支持了支持同一账号多处登录,所以seesionService 里面的session 对应的是一个session数组,如果,对session不做任何处理的话,没刷新一次页面,都会对这个session
数组自增 1.从暴露的api,我们可以看出,这个SessionService 可以用于对连接在前端服务器的客户端,踢下线,或者利用session id 直接在前端服务器发消息给客户端。
LocalSessionService 由于SessionService只存在于前端服务器(frontend),如果想在后端服务器(Backend)操作SessionService的话,就需要一个代理类(因为这是两个进程),从源码中可以看到,这个就是从前端服务器复制出来用于backend进行操作的SessionService,主要用于获取踢客户端下线,或者获取相关客户端Session Id。
LocalSession 是用于我们自定义的id 与全局 sessionService进行管理的类。主要用于服务端对客户端之间会话的管理。
从api 文档暴露的接口我们可以得知主要作用:
让我们自定义的id 可以绑定到客户端与服务端之间的会话,用于管理客户端的状态。例如,利用绑定的id实现控制对客户端进行踢掉,监听session的关闭事件。
localSession 还提供了一个K/V 的数据存取操作 需要用push或者pushAll 对sessionSerive进行更新。但是,根据官方的回复,不建议把session当做内存库。
###Session FAQ##
Session 是否适合当初内存数据库使用?
session里存的是只读的用户状态数据, 不会同步到数据库。 内存数据的同步是另一个模块实现的。不要把session当成内存数据库使用, session会在各服务器节点间传递, 因此session的内容越少、越轻量越好。
问题及答案来自于:谁能帮我介绍一下 pomelo的session 用法?
localSessionService和sessionService的区别?
如果看完本章节还是不明白的话?
可以参见有没有文档具体解释localSessionService和sessionService?
如何在connector以外的服务器中获取全局session?
如何在connector以外的服务器中获取全局session
uid 不能为object
问题来源于 :
fail to send message by uid for session not exist
##扩展阅读##ES 5的 bind()方法。
在pomelo的一些demo 里面可能会不理解这么一句话
session.on('closed', onUserLeave.bind(null, this.app)); var onUserLeave = function(app, session) { if(!session || !session.uid) { return; } app.rpc.chat.chatRemote.kick(session, session.uid, app.get('serverId'), session.get('rid'), null); };
你可能会有这样的疑问
为什么onUserLeave 会有两个参数?
函数的bind() 第一个参数null 什么什么意思,结合第一个问题,这里就传了一个参数?那么那个session 还是怎么传过来的?
这个函数 bind() 方法是ES 5 新增的一个特性。用于将函数绑定到某个对象上。
那么这里bind()的方法的作用是什么呢?
要明白这里的bind()的用法,首先我们需要了解一种函数式编程技术—柯里化(currying)
Wiki是这么定义的:
在计算机科学中,柯里化(Currying),是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数而且返回结果的新函数的技术。
为了帮助理解这里写一个小例子(来自于Javascript 权威指南第六版 p191)
var sum = function(x, y){ return x+y; } //创建一个类似于sum的新函数,但this的值绑定到null //并且第一个参数绑定到1, 这个新函数的期望只传入一个实参 var succ = sum.bind(null, 1); console.log(succ(2)); //输出 3; x 绑定到1,并传入2作为实参 //另外一个做累计计算的函数 var sum2 = function(y ,z){ return this.x + y + z; } //绑定this 和 y var bindSum2 = sum2.bind({x : 1}, 2); console.log(bindSum2(3)); //输出 6; this.x 绑定到1,y绑定到2, z 绑定到3.
上面这个例子就是柯里化的应用了,现在我们回到pomelo看下,chatpomelo例子里面怎么使用这个柯里化技术。
现在,应该能解决开头的第一个问题了,那么第二个问题,我们需要阅读一下pomelo的源码
阅读源码sessionService.js 464-478
从这十几行代码和柯里化的知识,我们就能够明白为什么onUserLeave为什么会有两个参数了。
var onUserLeave = function(app, session){ }
最后的参数是通过柯里化的技术把单参数 session 传到我们多参数函数里面。
这里有一篇讲柯里化技术挺有趣的文章:http://www.zhangxinxu.com/wordpress/2013/02/js-currying/
也欢迎到我的博客阅读。。http://blog.gfdsa.net/2013/06/05/pomelo
Pomelo 新手计划(四)
发布于 3 年前 作者 youxiachai 3492
次浏览
##前言##今天我们介绍一下Channel 广播机制和RPC 的使用。
##Channel##对于一个游戏服务器,而言,把消息推送给玩家,这是一个很基础的功能,在pomelo 里面用Channel 进行消息的推送服务,要进行消息的推送,Channel提供了两种方式:
匿名Channel
具名Channel
###匿名Channel###什么是匿名Channel?匿名Channel就是直接使用channelService进行消息推送,在api 中提供了两种方式
这种是指定用户Session 里面的绑定的UID(
session.bind(uid);)推送到那个session
uid 的方式有四个参数
route String type
msg Object type
uids Array Type
[{uid: userId, sid: frontendServerId}]
主要数组里面每个对象的属性
cb - cb(err) 错误的回调 例子:
var uidArray = new Array(); uidObject.uid = "session uid"; uidObject.sid = "connector-server-1"; uidArray.push(uidObject); channelService.pushMessageByUids('onMsg',{msg:msg},uidArray,function(err){ if(err){ console.log(err); return; } });
第二种就是把消息广播到所有连接在frontend 服务器的客户端.
stype String type
指定我们需要广播的frontend 类型,注意这里不是frontend id 而是类型,例如
connector
如果你配了多台服务器,消息会广播到所有连接在这种类型frontend的客户端上。
route String type
如 ‘onMsg’
msg Object type
opts Object type
自0.4.x 的配置只有一个参数 opts.binded Boolean typetrue 根据session 的uid 进行广播,false 根据session的id 进行广播
cb
channelService.broadcast('connector' ,'onMsg', msg, {binded: true}, function(err){ if(err){ console.log(err); } });
###具名Channel###具名Channel 就是我们在pomelo 创建一个推送房间。用于维护需要长期订阅关系的业务,例如,聊天的频道,注意使用具名Channel 如果那个Channel不在使用,需要显式调用销毁接口。
例子:
//创建Channel var channelName = 'allPushChannel'; var channel = this.channelService.getChannel //把用户添加到channel 里面 if(!!channel){ channel.add(uid, sid); }
//根据Channel 名字推送消息 var channelName = 'allPushChannel'; var pushChannel = this.channelService.getChannel(channelName, false); pushChannel.pushMessage('onMsg',{msg: msg}, function(err){ if(err){ console.log(err); }else{ console.log('push ok'); } });
以上就是pomelo 有关推送的全部内容,用pomelo进行消息的推送就是这么简单!
##RPC使用##从pomelo 框架图里面我们可以知道,pomelo 是一个多进程相互协作的环境。关于这方面的pomelo是如何实现的可以阅读官方的Pomelo Framework
这里不再对pomelo如何实现rpc 进行描述,针对原文档的一些不清晰的地方进行补充。
如何使用rpc 服务,让frontend 能够调用backend 的方法?
要实现这个目的很简单。根据Pomelo 的相关阅读。首先在handler 同级目录下创建一个remote目录,创建一个
backendRemote文件(具体可以参考分布式聊天的例子)
值得注意的是,我们调用远程方法的时候,第一个参数需要是Session值。
//远程服务端 backend.kick = function(uid, sid){ } //调用远程服务的时候,我们要需要从app 获得rpc服务 var rpc = app.rpc; //代理端的完整写法 rpc.frontend.kick = function(session, uid, sid){ }
以上就是pomelo 多进程相互协作的使用方式
也欢迎到我的博客上面阅读。。。http://blog.gfdsa.net/2013/06/06/pomelo_study_four/
Pomelo 新手周计划(二)
发布于 3 年前 作者 youxiachai 3433
次浏览
##前言##昨天,简要的介绍了客户端如何发起对Pomelo的请求和处理pomelo响应,今天,我们说一下,Pomelo服务端如何处理请求响应以及如何开始我们服务端代码的编写。
##Pomelo 请求与响应##
Pomelo请求响应流程图。
在pomelo 请求响应模型中,它只有三层。
发起请求与响应的客户端。
接受,响应请求的Frontend。
处理Frontend 请求与响应的Backend。
在昨天,我们已经知道了如何利用frontend进行与客户端的通信,那么什么是Backend?
我先来看一下官方的定义:
Frontend(connector)
用于面向客户端的连接
维护Session信息
分发请求给Backend
推送消息给客户端
Backend
处理来自于Frontend的请求
通过Channel 或者 Response 推送请求给frontend
Rpc 服务
从以上定义中,我们可以这么认为,Frontend 是用于面向客户端请求的服务器,用于维护当前的连接数以及让客户端能够访问Backend 的桥梁,而Backend 用于处理游戏的逻辑。
为了方便了解,我们可以阅读官方提供的框架图。
###创建Frontend和Backend###Pomelo 有一个特点就是通过对目录和命名约定进行来进行对组件的创建。现在我们去到
./game-server/app/servers/
我们所有关于frontend和backend的代码都有在该目录下创建。
创建规则###Frontend的创建###
servers ├─connector │ └─handler │ entryHandler.js
第一级目录为servers Type,就是定义这个在服务端处于什么类型,例如,我们要创建一个
gate
类型的服务用于负载均衡的话,我们只需要创建一个把
connector
改为
gate。
第二级目录约定为handler,所有处理请求的js文件都放在该目录下面。
entryHandler.js这个文件为我们处理请求和响应的文件。
以上规则就是我们在Pomelo 里面要响应对客户端请求的步骤。然后,我们只需要在配置文件上面做一些修改,Pomelo在启动的时候就会加载我们创建好的frontend了。(详情阅读声明使用Frontend和Backend)
对于客户端而言只要在请求的时候对应以上规则即可
阅读hello world项目 /public/index.html 大概19 -36行代码
pomelo.request("connector.entryHandler.entry", "hello pomelo", function(data) { alert(data.msg); });
假如我们常见了一个gate的 frontend 用于负载均衡我们在客户端只需要做如下修改就能进行对gate的访问了。
pomelo.request("gate.entryHandler.entry", "hello pomelo", function(data) { alert(data.msg); });
###Backend的创建###
servers └─testBackend ├─handler │ entryHandler.js │ └─remote testBackendremote.js
规则与frontend基本一致,不过多了一个remote目录,用于RPC 的处理。然后,我们只需要在配置文件上面做相关配置,pomelo在启动的时候就会加载我们创建好的Backend。(详情阅读声明使用frontend,backend)
接着客户端如果要访问Backend 需要先连接接Frontend 再从回调中发起对Backend的访问。
client -> frontend -> backend 这个过程不可越过
hello world项目 /public/index.html 大概19 -36行代码增加。
pomelo.request("connector.entryHandler.entry", "hello frontend", function(data) { pomelo.request("testBackend.entryHandler.entry", "hello backend", function(data) { alert(data.msg); }); });
做了以上的修改以后,客户端就能对服务端的Backend发起请求并且响应。
##配置Frontend和Backend##上面我们知道了如何在服务端创建Frontend,Backend规则,那么Pomelo如何加载我们的定义好的的frontend,和backend 呢?
要让pomelo 加载我们创建好的frontend和backend 需要在
./game-server/config/servers.json作以下修改。因为development与production的设置是一样的这里就以development为例
{ "development": { "connector": [ { "id": "connector-server-1", "host": "127.0.0.1", "port": 3150, "clientPort": 3010, "frontend": true } ], "testBackend": [ { "id": "test-server-1", "host": "127.0.0.1", "port": 3151 } ] } }
###Frontend配置说明###
对于frontend 对象而言
"connector": [ { "id": "connector-server-1", "host": "127.0.0.1", "port": 3150, "clientPort": 3010, "frontend": true } ]
id 就是该frontend的在服务器的名字
host 服务器的地址
port 服务器的端口号
clientPort 客户端用于连接的端口号
frontend 是否是一个frontend
###Backend配置说明###backend对象基本与frontend一致,只是少了面向客户端端口的声明
"testBackend": [ { "id": "test-server-1", "host": "127.0.0.1", "port": 3151 } ]
id 就是该frontend的在服务器的名字
host 服务器的地址
port 服务器的端口号
###添加服务器###对于Pomelo而言,添加服务器只需要在配置文件中作如下修改,这样我们就添加多了一台connector的服务器了,如果要添加一台backend服务器,也是一样的道理。
"connector": [ { "id": "connector-server-1", "host": "127.0.0.1", "port": 3150, "clientPort": 3010, "frontend": true }, { "id": "connector-server-2", "host": "127.0.0.1", "port": 3151, "clientPort": 3011, "frontend": true } ]
##总结##今天,对于Pomelo的理解:
服务端
如何进行请求响应。
如何创建我们一个frontend或者backend。
如何通过配置文件让pomelo加载我们的frontend和backend。
客户端
客户端如何发起对backend请求。
##资料来源##pomelo 官方wiki
也欢迎到我的博客阅读:http://blog.gfdsa.net/2013/
相关文章推荐
- JAVA与指针
- PHP、JS间json数据的处理
- mysql修改表、字段、库的字符集
- 1106. Lowest Price in Supply Chain (25)
- ZOJ 3430 detect the virus AC自动机
- 设计模式总结
- 走进小作坊(九)----省时省力的二八法则
- Ben Horowitz:执行程序有多糟糕,公司倒闭就有多快
- [按钮点击事件的几种方法]
- 严蔚敏数据结构单链表的所有基本操作
- (转)protein 数据库
- 统计题3
- UML学习(类图和序列图等)
- 将要改变IT世界的的docker技术是什么?
- Java——Java 中新增的 foreach 的用法
- JVM(三)
- Memcache知识点梳理
- git总结(6)里程碑,分支,远程版本库
- leetcode刷题日记——Merge Sorted Array
- Android.mk中的经常使用语法