您的位置:首页 > 其它

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/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: