当前位置:   article > 正文

【Unity】 在Unity中实现Tcp通讯(4)———心跳机制_unity如何做心跳机制

unity如何做心跳机制

前几篇内容,分别阐述了Unity中实现Tcp通讯的客户端、服务端的实现以及引入ProtoBuf进行数据序列化的方式。

这篇来写一下心跳机制。

 

第二篇内容中,对于客户端是否断开连接,是通过判断接受到的数据流是否是空来判断连接是否断开。

代码是这样的:

  1. int length = m_Socket.EndReceive(ir);
  2. if(length < 1)
  3. {
  4. IPEndPoint endPoint = m_Socket.RemoteEndPoint as IPEndPoint;
  5. Console.WriteLine("客户端:" + endPoint.Address.ToString() + "已断开连接");
  6. Close();
  7. return;
  8. }

 

显然用这种方式是不足以说明客户端真的已经断开连接的

因此这里就需要引入心跳机制来解决这个断开问题。

 

一.心跳机制

所谓心跳机制,就是服务端每隔一段时间向客户端发送一个空包

若客户端不能在规定时间内做出应答则认为连接已断开。

 

而且心跳机制这个名字也非常具有象征意义,它就像人的心脏跳动一样,按照一定频率不断的去确认客户端是否还“活着”。

人的心脏如果不跳了,那么人肯就是死了,而客户端如果不能做出应答,也就像人的心脏停止跳动一样,“死了”。

 

下面就在第二篇的代码的基础上实现心跳机制。

 

二.实现心跳机制

 

1.心跳计时器

既然是按照一定频率来发送空包,肯定就要使用计时器去触发了,这里直接构造一个System.Threading.Timer的计时器对象,每隔15000毫秒(15秒)触发一次

m_HeartBitTimer = new Timer(HeartBit, 0, 0, 15000);

2.使用时间戳来计算心跳间隔时间

上面说过,心跳需要每隔一段时间触发一次,因此这里需要采用时间戳来计算触发时间。

时间戳就是从过去到现在的一段时间,使用两个时间戳相减即可得到这中间流逝的时间。

比如服务器启动时间是2020年6月9日14点30分0秒,那么:

从服务器启动到当前所经过的时间 = 从1970年1月1日0分0秒到当前的时间 - 从1970年1月1日0分0秒到2020年6月9日14点30分0秒。

若心跳每隔15秒触发一次,则这个差值大于等于15的时候就开始执行心跳逻辑。

采用时间戳的好处就是,不需要实时累计,在需要的时候计算一下即可得到精确的差值。

而实时累加由于精度问题,往往会产生一定误差,且需要不断累计比较繁琐。

 

  1. private void HeartBit(object state)
  2. {
  3. TimeSpan ts = DateTime.Now - new DateTime(1970, 1, 1, 0, 0, 0, 0);
  4. if (m_TimeStamp == 0) m_TimeStamp = ts.TotalSeconds;
  5. if(ts.TotalSeconds - m_TimeStamp > DIS_CONNECT_TIME)
  6. {
  7. if (!m_IsCheckHeart)
  8. {
  9. m_IsCheckHeart = true;
  10. m_TimeStamp = ts.TotalSeconds;
  11. Send(1, new byte[0]);
  12. }
  13. else
  14. {
  15. Close();
  16. }
  17. }
  18. }

这里DateTime.Now - new DateTime(1970, 1, 1, 0, 0, 0, 0)即是从1970年1月1日0点0分0秒开始到目前为止的一段时间,使用秒做单位

m_TimeStamp是一个标志位,它记录的是一次心跳发生之前的时间,ts.ToalSecondes - m_TimeStamp也就是当前时间和一次心跳发生前的时间的差值,即从一次心跳之前到现在过去了多久。 DIS_CONNECT_TIME就是一个触发时间的常量,这里定义为15秒。

 

3.收包处理

因为这里把编号为1的包作为心跳包,所以在收包的时候要对编号为1的包进行特殊处理:收到1号包的时候把时间戳归0,等待下一次心跳触发。

  1. private void CheckReceiveBuffer(object state)
  2. {
  3. lock (m_ReceiveQueue)
  4. {
  5. if (m_ReceiveQueue.Count < 1) return;
  6. byte[] buffer = m_ReceiveQueue.Dequeue();
  7. byte[] msgContent = new byte[buffer.Length - 2];
  8. ushort msgCode = 0;
  9. using (MemoryStream ms = new MemoryStream(buffer))
  10. {
  11. byte[] msgCodeBuffer = new byte[2];
  12. ms.Read(msgCodeBuffer, 0, msgCodeBuffer.Length);
  13. msgCode = BitConverter.ToUInt16(msgCodeBuffer, 0);
  14. ms.Read(msgContent, 0, msgContent.Length);
  15. }
  16. if (msgCode == 1)//若收到编号为1的心跳包,则把时间戳归0,等待下一次心跳触发
  17. {
  18. m_IsCheckHeart = false;
  19. m_TimeStamp = 0;
  20. }
  21. else
  22. {
  23. text content = ProtoBufUtil.BytesToObject<text>(msgContent, 0, msgContent.Length);
  24. Console.WriteLine("消息编号:" + msgCode + ",内容:" + content.content);
  25. }
  26. }
  27. }

 

 

好了,心跳到这里也写完了。

Unity Tcp部分我写了4篇文章,算是把整个流程说了大概。

总的来说,这也是对我自己关于这部分知识的一个梳理。

接下来我会写一些关于unity中的行为树,状态机,UI框架,资源管理框架,优化等内容的文章。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/盐析白兔/article/detail/720075
推荐阅读
相关标签
  

闽ICP备14008679号