Unity3D网络-心跳包

2018-06-04  本文已影响407人  passiony

握手过程中传送的包里不包含数据,三次握手完毕后,客户端与服务器才正式开始传送数据。理想状态下,TCP连接一旦建立,在通信双方中的任何一方主动关闭连接之前,TCP 连接都将被一直保持下去。断开连接时服务器和客户端均可以主动发起断开TCP连接的请求,断开过程需要经过“四次握手”(过程就不细写了,就是服务器和客户端交互,最终确定断开)

什么是心跳

刚才说到长连接建立连接后,理想状态下是不会断开的,但是由于网络问题,可能导致一方断开后,另一方仍然在发送数据,或者有些客户端长时间不发送消息,服务器还维持这他的客户端不必要的引用,增加了服务器的负荷。因此我们引入了心跳机制。

心跳包之所以叫心跳包是因为:它像心跳一样每隔固定时间发一次,以此来告诉服务器,这个客户端还活着。事实上这是为了保持长连接,至于这个包的内容,是没有什么特别规定的,不过一般都是很小的包,或者只包含包头的一个空包。

总的来说,心跳包主要也就是用于长连接的保活和断线处理。一般的应用下,判定时间在30-40秒比较不错。如果实在要求高,那就在6-9秒。

怎么发送心跳?

心跳比起轮询有两个优势:
1.避免服务端的压力
2.灵活好控制


代码演示

服务器端

 private ServerManager()
    {
        IPAddress address = IPAddress.Parse(IP);
        listener = new TcpListener(address, Port);
        //绑定ip和port,进行侦听
        listener.Start();
        Console.WriteLine("开始侦听");

        //异步监听客户端连接
        listener.BeginAcceptTcpClient(OnAccecpt,null);
  
        //开启定时器System.Threading.Timer
        Timer timer = new Timer(Callback,null, HeartInterval, HeartInterval);
        
        //定时器System.Timers
        //System.Timers.Timer t = new System.Timers.Timer();
        //t.Interval = 1000;//定时器间隔
        //t.Elapsed += delegate (object sender, System.Timers.ElapsedEventArgs e){ };
        //t.Enabled = true;//开启定时器
    }

    void Callback(object state)
    {
        List<string> keys = new List<string>();
        foreach (var item in dic.Keys)
        {
            keys.Add(item);
        }
        for (int i = 0; i < keys.Count; i++)
        {
            SocketClient client = dic[keys[i]];
            client.SendMessage(Protocol.HeartBeat);
            client.timeOut++;
            if(client.timeOut>5)//4次心跳超时,服务器比客户端多判断一次
            {
                Console.WriteLine(client.userdata.username+ "心跳超时,断开链接");
                RemoveClient(client);
            }
        }
    }
 //接收客户端消息,并进行分发
    public void OnMessage(SocketClient client,int protocol,string msg)
    {
        switch (protocol)
        {
            case Protocol.Login_CMD:
                break;
            case Protocol.HeartBeat:
                //接收到心跳,重置timeOut
                client.timeOut = 0;
                break;
            default:
                break;
        }
    }

客户端

//接收到服务器心跳
    void OnHeatBeat()
    {
        lastHeartTime = Time.time;
        count = 0;
        //返回心跳
        SendMessage(Protocol.HeartBeat);
    }

    float lastHeartTime = 0;
    int count = 0;
    void CheckHeat()
    {
        if(client.online && client.isloggin)
        {
            if (Time.time - lastHeartTime > 5)//心跳超时
            {
                count++;
                lastHeartTime = Time.time;
                Debug.Log("心跳超时一次");
                if (count >= 3)//心跳超时3次
                {
                    count = 0;
                    Debug.Log("心跳超时3次,断线处理");
                    //断线处理
                    client.OnClose();
                }
            }
        }
    }
上一篇 下一篇

猜你喜欢

热点阅读