- 服务器是如何将消息推送给客户端的呢?
频道channel
是推送消息的工具,频道是玩家ID的集合,可以将玩家ID加入到某个频道,同样也可以从中移除。如果通过频道来推送消息,那么频道中的所有成员都将收到这条消息。可以创建多个频道来自定义消息推送区域,这些频道相互之间是独立的。
频道与广播
大部分的消息都是通过广播推送到客户端,再由客户端播放接收的消息。而channel则是服务器向客户端消息广播的通道。
channel
可以看作是玩家ID的容器,主要用于需要广播推送消息的场景。可以把玩家加入到一个channel
中,当对这个channel
推送消息时,所有加入到这个channel
的玩家都会受到推送过来的消息。一个玩家的ID可能会加入多个channel
中,这样玩家就会受到其加入的channel
推送过来的消息。
channel只是用服务器进程本地,channel
都是服务器本地的,应用服务器A和B并不会共享channel
,也就时说在服务器A上创建的channel
只能由服务器A才能给它推送消息,服务器进程A创建的channel和在服务器进程B创建的channel是两个不同的channel,相互不影响。
频道类型
pomelo中拥有两种频道分别是具名频道和匿名频道
- 具名频道
创建一个具名频道时,需要为其指定一个频道名称才会返回一个频道实例,具名频道并不会自动释放,需要调用channel.destroy()
方法来手动进行释放。具名频道通常用来保持长时间关系的订阅,比如聊天服务。
- 匿名频道
匿名频道是通过channelService.pushMessageByUids
来使用的,没有频道名称也没有频道实例返回。匿名频道用于频道成员变动频繁或推送临时消息时,比如AOI(Area of Interest)消息,当玩家在一个场景中从A点移动到B点时,服务器就需要推送一个AOI(Area of Interest)消息给周围玩家。
具名频道和匿名频道本质上都是相同的,即使看起来是不同的。首先频道需要将连接至它们的前端服务器分组,然后需要将消息联通玩家ID通过分组一起推送到各自的前端服务器,最后分发到各自客户端。
频道与推送
pomelo服务器和客户端保持长连接,推送可以根据频道推送或根据用户连接的服务器推送。
根据频道推送
创建频道
//创建频道
//channelName 表示频道的名字
//isCreate 表示是否在没有该频道时创建一个
let channel = this.app.get("channelService").getChannel(channelName, isCreate);
频道添加用户
//将用户添加到频道
//uid表示用户唯一标识
//sid表示connector服务器的ID
channel.add(uid, sid)
根据频道推送
//创建频道
let channel = this.app.get("channelService").getChannel(channelName, isCreate);
//根据频道推送
//event表示客户端监听的push方法,比如onAdd。
//msg表示推送参数
//cb表示推送后的回调函数
channel.pushMessage(event, msg, cb);
根据客户端连接推送
定义保存用户唯一编号和connector服务器的对应管理
let uids = [];
uids.push({uid:uid, sid:sid});
使用频道服务根据uids进行推送
//创建频道
//method表示客户端监听的push方法,比如onAdd。
//param表示推送参数
let channel = this.app.get("channelService").pushMessageByUids(method, param, uids);
频道API
/**
* Add user to channel.
*
* @param {Number} uid user id
* @param {String} sid frontend server id which user has connected to
*/
Channel.prototype.add = function(uid, sid)
/**
* Remove user from channel.
*
* @param {Number} uid user id
* @param {String} sid frontend server id which user has connected to.
* @return [Boolean] true if success or false if fail
*/
Channel.prototype.leave = function(uid, sid)
/**
* Get channel UserAmount in a channel.
*
* @return {number } channel member amount
*/
Channel.prototype.getUserAmount = function()
/**
* Get channel members.
*
* <b>Notice:</b> Heavy operation.
*
* @return {Array} channel member uid list
*/
Channel.prototype.getMembers = function()
/**
* Get Member info.
*
* @param {String} uid user id
* @return {Object} member info
*/
Channel.prototype.getMember = function(uid)
/**
* Destroy channel.
*/
Channel.prototype.destroy = function()
/**
* Push message to all the members in the channel
*
* @param {String} route message route
* @param {Object} msg message that would be sent to client
* @param {Object} opts user-defined push options, optional
* @param {Function} cb callback function
*/
Channel.prototype.pushMessage = function(route, msg, opts, cb)
频道服务ChannelService
ChannelService频道服务用于服务器本地创建和维护的频道,频道服务由默认加载的频道组件创建,pomelo和频道服务的组件可由app.get("channelService")
访问获取。
const channelService = app.get('channelService');
内置服务通过set函数挂载到app全局对象上,相当于服务变成了单例类,从而直接从this.app.get("channelService")
获取之前注册的服务,根据玩家uid和绑定的sid确定下来是哪个服务器,哪个channel。
/**
* Push message by uids.
* Group the uids by group. ignore any uid if sid not specified.
*
* @param {String} route message route
* @param {Object} msg message that would be sent to client
* @param {Array} uids the receiver info list, [{uid: userId, sid: frontendServerId}]
* @param {Object} opts user-defined push options, optional
* @param {Function} cb cb(err)
* @memberOf ChannelService
*/
ChannelService.prototype.pushMessageByUids = function(route, msg, uids, opts, cb)
/**
* Create channel with name.
*
* @param {String} name channel's name
* @memberOf ChannelService
*/
ChannelService.prototype.createChannel = function(name)
/**
* Get channel by name.
*
* @param {String} name channel's name
* @param {Boolean} create if true, create channel
* @return {Channel}
* @memberOf ChannelService
*/
ChannelService.prototype.getChannel = function(name, create)
/**
* Destroy channel by name.
*
* @param {String} name channel name
* @memberOf ChannelService
*/
ChannelService.prototype.destroyChannel = function(name)
/**
* Broadcast message to all the connected clients.
*
* @param {String} stype frontend server type string
* @param {String} route route string
* @param {Object} msg message
* @param {Object} opts user-defined broadcast options, optional
* opts.binded: push to binded sessions or all the sessions
* opts.filterParam: parameters for broadcast filter.
* @param {Function} cb callback
* @memberOf ChannelService
*/
ChannelService.prototype.broadcast = function(stype, route, msg, opts, cb)