正常的客户端与服务器的通讯中,一般都是客户端发送一个请求,服务器返回一个响应,但是这种主动的请求与响应有的时候可能不能满足我们的需求,有的时候,我们需要一种可以随时发送响应的机制,比如说,在公会系统中,我们想要罢免、升职、踢出某个公会成员,正常的操作就是发送请求,接收响应,然后对响应进行一系列的处理。
但是换一个角度来想,因为一个响应能包含的信息有很多,如果我们可以在一个响应中把某些信息一起填充进要发送的数据中,这样是不是更高效一点?
拿mmorpg游戏举例,在完成地图中角色同步之后,假设当前有两个角色,角色1与角色2,当角色2移动的时候,他的位置是不断更新的,那么角色1会无时无刻的都能接收到角色2位置更新的数据,如果把公会任职、踢出等数据更新的消息,填充到我们在这个时候发送的数据中,在客户端接受数据之后,再通过事件、委托等一系列监控手段来进行数据修改的跟踪,这样岂不是能省很多事?
当然也存在缺点,如果当前的场景中玩家很少,可能角色1收不到任何消息,这个后处理机制就无法完成我们要的功能,但是事情哪有完美的呢,而且一般来说,在当前比较火爆的游戏中是不会发生这样的事情的。
所以说,这种机制只是适合那种对于及时性要求不是很高的消息,如果消息所要求的及时性很高,还是做那种一发一回的模式吧
拿公会系统举例
主要代码
1.通过更新时间戳来判断是否是当前
public void PostProcess(NetMessageResponse message)
{
Log.InfoFormat("PostProcess>Character:CharacterID:{0}:{1}", this.Id, this.Info.Name);
this.friendManager.PostProcess(message);
if(this.Team!=null)
{
Log.InfoFormat("PostProcess>Team:Character:{0}:{1} {2}<{3}", this.Id, this.Info.Name, TeamUpdateTs, this.Team.timestamp);
if(TeamUpdateTs<this.Team.timestamp)
{
TeamUpdateTs = Team.timestamp;
this.Team.PostProcess(message);
}
}
if(this.Guild!=null)
{
Log.InfoFormat("PostProcess>Guild:characterID:{0}:{1} {2}<{3}", this.Id, this.Info.Name, GuildUpdateTS, this.GuildUpdateTS);
if(this.Info.Guild == null)//如果角色的公会信息为空的话
{
this.Info.Guild = this.Guild.GuildInfo(this);//收到后处理的时候把角色身上的公会信息添加
if (message.mapCharacterEnter != null)//如果不是第一次登录就设置一下时间戳
GuildUpdateTS = Guild.timestamp;
}
//在这里,只要时间戳更新了,这里的逻辑就会执行
if(GuildUpdateTS <this.Guild.timestamp && message.mapCharacterEnter == null)
{
GuildUpdateTS = Guild.timestamp;
this.Guild.PostProcess(this, message);//一旦执行,那么公会的信息就会更新
}
}
if (this.StatusManager.HasStatus)
{
this.StatusManager.PostProcess(message);
}
}
2.
public void PostProcess(Character from,NetMessageResponse message)
{
if(message.Guild == null)//如果当前角色有公会
{
message.Guild = new GuildResponse();
message.Guild.Result = Result.Success;
message.Guild.guildInfo = this.GuildInfo(from);//更新时间戳之后,把当前公会的信息重新赋值、
//什么时候调用呢?
}
}
3.填充进要发送的数据中
public byte[] GetResponse()
{
if (response != null)
{
if (PostResponser != null)
this.PostResponser.PostProcess(Response);
byte[] data = PackageHandler.PackMessage(response);
response = null;
return data;
}
return null;
}
4.随着其他消息的发送一并发送公会更新后的数据
public void SendResponse()
{
byte[] data = session.GetResponse();
this.SendData(data, 0, data.Length);
}
5.调用位置
void SendCharacterLeaveMap(NetConnection<NetSession> conn, Character character)
{
。。。
conn.Session.Response.mapCharacterLeave = new MapCharacterLeaveResponse();
conn.Session.Response.mapCharacterLeave.entityId = character.entityId;
conn.SendResponse();
}
private void OnFriendAddRequest(NetConnection<NetSession> sender, FriendAddRequest request)
{
。。。
if(request.ToId>0)
{
if(character.friendManager.GetFriendInfo(request.ToId)!=null)
{
sender.Session.Response.friendAddRes = new FriendAddResponse();
sender.Session.Response.friendAddRes.Result = Result.Failed;
sender.Session.Response.friendAddRes.Errormsg = "好友已经存在";
sender.SendResponse();
return;
}
friend = SessionManager.Instance.GetSession(request.ToId);
}
。。。
}
也就是任何要发送数据的地方皆可调用
新手上路,若写的不对,请多指教!