一、问题场景还原
在做团队一款德州扑克的项目,玩家登陆游戏进入大厅前需要接收大量数据,包括公告、任务、签到、好友等等。服务器将大量的数据在较短的时间内发送给客户端导致客户端无法处理完,导致尾部的消息数据丢失。
玩家登陆后服务器需要发送的数据如下:
1 /// <summary> 2 /// 玩家数据 3 /// </summary> 4 /// <param name="player"></param> 5 public static void SendPlayerBaseInfo(Player player) 6 { 7 Debug.Log(string.Format("110 获取玩家基本信息,playerId={0}", player.PlayerId)); 8 var pk = PacketSend.Create(Event_PlayerBaseInfo.EventId); 9 PacketSet2(pk, player); 10 App_GateWayConn.Send(player.baseInfo.connId, pk); 11 12 ////好友上线 13 HandleFriend.SendFriendOnline(player); 14 } 15 /// <summary> 16 /// 玩家数据 17 /// </summary> 18 /// <param name="player"></param> 19 public static void SendPalyerInfo1(Player player) 20 { 21 //众筹信息 22 HandleCrowfund.Handle_PlayerLogin(player); 23 24 } 25 /// <summary> 26 /// 玩家数据 27 /// </summary> 28 /// <param name="player"></param> 29 public static void SendPalyerInfo0(Player player) 30 { 31 //公告 32 HandleSys.Handle_SendNotice(player); 33 //任务 34 HandleTask.SendInfo(player); 35 //签到 36 HandleSign.SendInfo(player); 37 //游戏数据 38 SendPlayerComInfo(player); 39 40 #region 场次信息 41 HandleTournament.HandleTournament_List(player); 42 HandleTournament.HandleTournament_SendEnrolledInfo(player); 43 HandleSitFullRoom.Handle_SendList(player); 44 HandleSitFullRoom.Handle_SendSession(player); 45 HandleEliminateRoom.HandleEliminate_SessionList(player); 46 HandleEliminateRoom.HandleEliminate_EnrolledInfo(player); 47 #endregion 48 //好友 49 HandleFriend.Handle_Send(player); 50 51 //邮件 52 HandleMail.SendMails(player); 53 //礼包 54 HandleGift.Handle_Send(player); 55 56 //商品信息 57 HandleShop.Handle_Login(player); 58 }
二、解决方法
逻辑图如下:
添加一个协议页管理协议(协议号:20),目的是控制服务器每次向客户端连续发送数据协议个数。
协议页管理协议:
1 /// <summary> 2 /// 20 登陆消息页管理 3 /// </summary> 4 public class Event_EventPage:EventBase 5 { 6 //协议号 20 7 public const ushort EventId = 20; 8 public byte page; 9 public override ushort GetEventId() { return EventId; } 10 public static EventBase Create() { return new Event_EventPage(); } 11 public override void SetPacket(ArrByteReader reader) 12 { 13 page = reader.ReadByte(); 14 } 15 }
服务器向客户端发送协议页码:
1 /// <summary> 2 /// 发送消息管理页码 3 /// </summary> 4 /// <param name="player">玩家</param> 5 /// <param name="page">页码</param> 6 public static void Handle_EventPage(Player player, int page) 7 { 8 var pk = PacketSend.Create(Event_EventPage.EventId); 9 pk.Write((byte)page); 10 App_GateWayConn.Send(player.ConnId, pk); 11 }
服务器根据客户端请求指定页的协议数据管理:
1 /// <summary> 2 /// 20 登陆消息页管理 3 /// </summary> 4 public static void Handle_EventPage(EventBase eb) 5 { 6 var e = eb as Event_EventPage; 7 Player player; 8 if (!App_Player.GetPlayerByConnId(e.connId, out player)) 9 { 10 HandleCommon.SendState(eb, 0); 11 return; 12 } 13 Handle_SendEventPage(player, e.page); 14 15 } 16 /// <summary> 17 /// 发送给玩家指定协议页数据 18 /// </summary> 19 /// <param name="player"></param> 20 /// <param name="page"></param> 21 public static void Handle_SendEventPage(Player player, int page) 22 { 23 switch (page) 24 { 25 case 0: 26 SendPalyerInfo0(player); 27 Handle_EventPage(player, page+1); 28 break; 29 case 1: 30 SendPalyerInfo1(player); 31 Handle_EventPage(player, page + 1); 32 break; 33 case 2: 34 SendPlayerBaseInfo(player); 35 break; 36 case 3: 37 break; 38 default: 39 break; 40 } 41 }
玩家登陆后服务器向客户的发送第0页协议数据 Handle_SendEventPage(player,0),
服务器发送完第0页协议数据后会会接着发送协议20,将下一页的协议页码1发给客户端,客户端处理完第0页后会处理协议20,将通过页码1请求第1页协议数据,依次类推,直到服务器不在给客户端发送协议20,最终发送进入游戏大厅协议。