手机游戏断线重连的实现

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)这样双方就重连完成

注意:

  其实在实际运用中会有很多特殊情况:重连中有可能再次断网、登陆时断网、连接多次超时或者序号已经相差很大时等特殊处理、服务器缓存优化等问题这都是逻辑问题,并不是我们断线重连的核心内容这里就不做阐述了

猜你喜欢

转载自blog.csdn.net/lejian/article/details/124425730