1、断线重连的必要性
在端游时代,因为游戏环境比较固定,断网的可能比较小,断线重连就没有那么重要,甚至有的游戏都没有断线重连,判断你断线了直接返回到登录界面,走重新登录的流程。
但在移动设备的情况下,环境非常不固定,网络也有可能非常不稳定,如果按照早期的端游的做法,直接走登录流程,那用户的体验感就非常的不好。
当然也有的判断断线了直接将网络connect上就好了,但是并没有那么简单。因为用户的操作是不确定的,用户有可能在停留在任意界面。
比如:在抽卡的时候进入电梯,断网了,这时send (抽卡)message给服务器,等联网的时候
服务器并没有收到抽卡消息,这时大家想想会是什么样的情况,消息就丢失了。因为抽卡功能游戏氪金的一个重要系统,美术和策划小伙伴希望把这个功能做的绚丽点,可能分为几个步骤完成,下一步骤高度依赖于服务器上一条消息返回,中间任何消息的丢失都不行,丢失了都有可能会各种异常,对于客户端程序员来说通过特殊处理这种情况那就会欲仙欲死,痛苦务必。
所以我们要在底层实现一个一劳永逸的机制实现我们的消息正确性,断线重连消息正确性确认就尤为重要。
2、断线重连的思路及伪代码实现
//伪代码,消息的定义
message
{
int length; //消息长度
short msgId; //消息ID
int seq; //消息序号
bytes body; //消息体
}
}
对于对于客户端和服务器都有两个变量sendSeq(本地发送序列号)和recvSeq(接收到的序列号)
sendSeq:
我发主动发送的序号,每次发送消息都会自增sendSeq++,sendSeq在特殊情况下不会更新。登陆、重连、心跳信号等消息除外,具体还有哪些消息根据业务情况自己定义。
recvSeq:
记录收到对方当前序列号,如果是message.seq非0的序号都会被记录;
1)客户端消息每次发送的必要消息(消息序号都会都会自增sendeq++,并将sendSeq赋值给message.seq;
2)客户对于必要消息进行存储(设定存储一定长度,如最大存储64条),如果缓存区大于最大缓存消息数量,那么就删除最早缓存的消息,保证缓存区存储的消息数量最多不大于设定最大阈值。
//发送消息处理伪代码函数
function sendMessage(message )
{
if(消息在忽略列表中)
{
message.seq = 0;
}
else
{
sendSeq++;
message.seq = sendSeq;
//缓存到发送列表中
if(cacheSendList.length>=MAX_CACHE_LENGTH)
cacheSendList.remove(0);
cacheSendList.add(message);
}
socket.send(message);
}
3)客户端收到接收到的服务器端消息,检查message.seq!=0更新recvSeq
//收到消息处理伪代码函数
function recv(message)
{
if(message.seq!=0)
recvSeq = message.seq;
//处理消息
handle(message);
}
4) 服务器端同理实1、2、3步,服务器的缓存过滤的消息包括:聊天、心跳、走马灯等非必要消息内容,它缓存的长度需要设置可以大于64条,根据实际情况而定
5) 客户端当检查到网络断开需要触发断线重连时,客户端断线重连界面(如:在登录中网络断开,并不需要触发重连,直接重新登录就是,只有进入游戏了才触发断线重连),客端发送LoginReconnectToken消息给服务器(附带token内容等验证内容)
//伪代码
LoginReconnectToken
{
string token;
string userId;
//其它内容
....
}
6)服务器验证token并返回BeginReconnect,告知客户端开始重连,并把服务器的recvSeq发给客户端
//伪代码
BeginReconnect
{
int32 seq;
//其他内容
...
}
7) 客户端收到服务器的BeginReconnect 消息,将客户端收到的重连前收到的recvseq通过BeginReconnect2返回服务器,并根据当前消息的seq比对发送缓存的消息,进行消息的补发
BeginReconnect2
{
int32 seq;
//其它内容
...
}
补发缓存区内容代码:
//发送重连消息伪代码函数,补发的消息序号sendSeq并不需要增加
sendReconnectMessage(seq)
{
foreach(message:cacheSendList)
{
if(message.seq <seq)
continute;
socket.send(message);
}
}
8)服务器收到客户端发过来BeginReconnect2消息,根据BeginReconnect2消息中所带seq对消息也进行补发
9)这样双方就重连完成
注意:
其实在实际运用中会有很多特殊情况:重连中有可能再次断网、登陆时断网、连接多次超时或者序号已经相差很大时等特殊处理、服务器缓存优化等问题这都是逻辑问题,并不是我们断线重连的核心内容这里就不做阐述了