Unity【Multiplayer 多人在线】- Socket 通用服务端框架(七)、时间戳和心跳机制

举报
CoderZ1010 发表于 2022/09/25 04:42:14 2022/09/25
【摘要】 介绍         在阅读了罗培羽著作的Unity3D网络游戏实战一书后,博主综合自己的开发经验与考虑进行部分修改和调整,将通用的客户端网络模块和通用的服务端框架进行提取,形成专栏,介绍Socket网络编程,希望对其他人有所帮助。目录如下: 一、通用服...

介绍

        在阅读了罗培羽著作的Unity3D网络游戏实战一书后,博主综合自己的开发经验与考虑进行部分修改和调整,将通用的客户端网络模块和通用的服务端框架进行提取,形成专栏,介绍Socket网络编程,希望对其他人有所帮助。目录如下:

一、通用服务端框架

        (一)、定义套接字和多路复用​​​​​​

        (二)、客户端信息类和通用缓冲区结构

        (三)、Protobuf 通信协议

        (四)、数据处理和关闭连接

        (五)、Messenger 事件发布、订阅系统

        (六)、单点发送和广播数据

        (七)、时间戳和心跳机制

 二、通用客户端网络模块

        (一)、Connect 连接服务端

        (二)、Receive 接收并处理数据

        (三)、Send 发送数据

        (四)、Close 关闭连接

本篇内容:

时间戳:

时间戳是记录时间的一种方式,指的是计算机元年开始到现在的秒数。那么什么是计算机元年?

历史背景:

1969年美国贝尔实验室的程序员肯汤普逊使用B编译语言在老旧的PDP-7机器上开发出了UNIX的一个版本。随后,他和同事丹尼斯里奇改进了B语言,开发出了C语言,并用C语言重写了UNIX,并于1971年发布了新版本。于是,一个伟大的时代拉开了序幕。

定义:

上古时期的计算机操作系统是32位,一个int类型的数据是32位,它表示的范围是:-2147483648 ~ 2147483647,用它来代表秒钟数进行计算:2147483647/(3652460*60)=68.1(年)
也就是说用这个数来表示时间如果从公元纪年(耶稣诞生)开始算显然不够用,所以综合当时UNIX的发展历程,取了1970年1月1日0时0分0秒做为计算机元年,用于计时的开始。

2038年问题:

32位表示最后时间到了2038年1月19日03时14分07秒,便达到了最大值,过了这个时间点,数据越界变成最小值:-2147483648。代表的时间就是1901年12月13日20时45分52秒,出现时间回归的现象,很多依赖时间的软件就会出现异常。

2038年以后怎么办:

发展所导致的问题只能通过进一步发展解决,随着64为操作系统的普及,现在用64位操作 系统可以表示到292277026596年12月4日15时30分08秒了。也就是2900亿年以后。

定义获取时间戳的方法:


  
  1. namespace SK.Framework
  2. {
  3. /// <summary>
  4. /// 时间类工具
  5. /// </summary>
  6. public class TimeUtility
  7. {
  8. /// <summary>
  9. /// 获取时间戳
  10. /// </summary>
  11. /// <returns>时间戳</returns>
  12. public static long GetTimeStamp()
  13. {
  14. TimeSpan ts = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0);
  15. return Convert.ToInt64(ts.TotalSeconds);
  16. }
  17. }
  18. }

心跳机制:

正常情况下,服务器每隔一段时间必然会收到客户端发送的PING协议,如果长时间没有收到,很大概率是客户端网络不通畅,此时便可以释放Socket资源。

心跳机制涉及PING和PONG两条协议,首先创建这两条协议的.proto文件,不需要定义任何字段,通过protoc.exe编译成.cs文件导入到项目中:

在客户端信息类Client中定义long类型字段lastPingTime,用于记录上一次收到该客户端PING协议的时间,pingInterval用于表示客户端发送PING协议的时间间隔:


  
  1. using System.Net.Sockets;
  2. namespace SK.Framework.Sockets
  3. {
  4. /// <summary>
  5. /// 客户端信息类
  6. /// </summary>
  7. public class Client
  8. {
  9. /// <summary>
  10. /// 套接字
  11. /// </summary>
  12. public Socket socket;
  13. /// <summary>
  14. /// 缓冲区
  15. /// </summary>
  16. public ByteArray readBuff;
  17. /// <summary>
  18. /// 上一次收到PING协议时间
  19. /// </summary>
  20. public long lastPingTime = 0;
  21. /// <summary>
  22. /// 时间间隔
  23. /// </summary>
  24. public static long pingInterval = 30;
  25. /// <summary>
  26. /// 构造函数
  27. /// </summary>
  28. /// <param name="socket">套接字</param>
  29. public Client(Socket socket)
  30. {
  31. this.socket = socket;
  32. readBuff = new ByteArray();
  33. lastPingTime = TimeUtility.GetTimeStamp();
  34. }
  35. }
  36. }

超时处理:

当服务端很久没有收到ProtoPing时,可以认为连接已经断开,定义CheckPing方法判断是否超时:


  
  1. //Ping检查
  2. private static void CheckPing()
  3. {
  4. long ts = TimeUtility.GetTimeStamp();
  5. foreach (Client client in clients.Values)
  6. {
  7. if (ts - client.lastPingTime > Client.pingInterval * 4)
  8. {
  9. Close(client);
  10. return;
  11. }
  12. }
  13. }

参考资料:

《Unity3D网络游戏实战》(第2版)罗培羽 著

https://zhuanlan.zhihu.com/p/55670069

文章来源: coderz.blog.csdn.net,作者:CoderZ1010,版权归原作者所有,如需转载,请联系作者。

原文链接:coderz.blog.csdn.net/article/details/124055856

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。