坦克大战Netty网络联机版项目笔记

坦克大战Netty网络联机版项目笔记

项目地址:https://github.com/2017403603/TankGame.git

一、单工,半双工,全双工区别

1. 单工

​ 数据只在一个方向上传输,不能实现双方通信。

2. 半双工

​ 允许数据在两个方向上传输,但是同一时间数据只能在一个方向上传输,其实际上是切换的单工。

3. 全双工

​ 允许数据在两个方向上同时传输。

img

二、项目中遇到的问题

1.联机坦克如何显示在同一区域?

​ 在服务器端定义一个HashMap,每次有玩家连接进服务器的时候,将玩家的id和通信channel一起存进HashMap中,以便在需要进行坦克之间通信的时候,能够及时找到相应坦克的channel进行通信,每次玩家移动坦克,将会把坦克的位置信息发送给服务器,服务器接收到的信息,依次遍历HashMap中所有的channel,将位置信息发送给所有玩家,实现联机。

2. 服务器中的channel异常了怎么办?

​ 如果服务器中的channel出现了异常,如客户端连接突然中断,则将服务器中HashMap的对应channel移除,并且close这个channel,以免造成服务器异常

​ 客户端优雅退出连接:发出特定消息,服务器端收到,将HashMap的对应channel移除,并且close。

3. 自定义传递消息协议

​ 每个坦克都需要和服务器端进行通信,通信所传递的消息我们封装成一个消息类,类的属性有xy坐标,方向、速度、分组等,消息类自定义了一些方法用于消息传递,如序列化、反序列化等;自定义协议内容:

  • 魔数,用来在第一时间判定是否是无效数据包
  • 版本号,可以支持协议的升级
  • 序列化算法,消息正文到底采用哪种序列化反序列化方式,可以由此扩展,例如:json、protobuf、hessian、jdk
  • 指令类型,是登录、注册、单聊、群聊… 跟业务相关
  • 请求序号,为了双工通信,提供异步能力
  • 正文长度
  • 消息正文

​ 每个玩家坦克都有一个独一无二的id,这个id由服务器端生成,用于表示不同玩家。

4. 接收到Tankjoinmsg消息类的逻辑处理(服务器保存所有状态)

  1. 是不是自己?
  2. 列表是不是有了?
  3. 发自己的一个Tankjoinmsg消息类

5. 如何实现整个界面事件联机

​ 例如,玩家坦克加入是一个事件,我们把它包装成一个协议类,同样玩家坦克移动、射击、爆炸、暂停游戏也是一个事件,也需要包装成一个协议类用于玩家坦克之间消息传递,我们抽象出一个父类Msg,之后所有的消息协议类都继承Msg,服务器端和客户端在每次接收到消息协议类时都会判断消息类型,并做出对应消息的后续处理;可以把对应消息的后续处理也封装到消息协议类之中,这样无论接收到什么消息,都只要消息自己处理,省去了判断消息类型的步骤。

6. 所有消息类型

  • TankJoinMsg类:当有新的玩家坦克加入游戏(服务器)时,向服务器端发送一个TankJoinMsg消息类,服务器端收到后立即将消息类转发给其他玩家,告诉其他玩家有新的坦克玩家加入,其他玩家收到消息后会判断本身客户端是否已经记录了这个坦克消息,如果没有记录,则发送自身的TankJoinMsg消息类(类的属性有xy坐标,方向、速度、分组等),如果已经记录,则说明这个坦克信息之前就有了,不用处理(每个客户端里面都有个list集合用于存储在线的玩家坦克信息,根据集合里面的内容画出对应玩家坦克);达到玩家坦克加入的画面同步。
  • TankDirChangedMsg类:当有玩家改变坦克方向时,向服务器端发送一个TankDirChangedMsg消息类,服务器端收到后立即将消息类转发给其他玩家,告诉其他玩家此坦克方向已经改变,所有客户端根据信息重新绘制坦克方向。(类的内容有当前xy坐标、更改后的方向、更改的玩家id)
  • **TankStopMsg/TankStartMovingMsg类:**当有玩家按下/松开移动键时,向服务器端发送一个TankStopMsg/TankStartMovingMsg消息类,服务器端收到后立即将消息类转发给其他玩家,告诉其他玩家此坦克移动/停止状态已经发送改变,所有客户端根据状态量重新绘制对应坦克移动/停止。(xy、dir、id)
  • BulletNewMsg类:当有玩家按下发射键时,该玩家向服务器端发送一个BulletNewMsg消息类,类的内容有子弹id、发射子弹的玩家id、要发射子弹的xy位置、子弹分组和子弹方向等,服务器端收到后立即将消息类转发给其他玩家,告诉其他玩家xy位置出现了一颗子弹,所有客户端收到子弹放入list并且绘制。
  • TankDieMsg、TankblastMsg、BulletdieMsg类…:这几个消息由服务器发送,服务器端控制着整局游戏的状态,子弹增加的时候公共资源部分也会修改增加,当公共资源部分检测到爆炸或者坦克消亡时,会给所有坦克玩家发送TankDieMsg、TankblastMsg、BulletdieMsg消息类,以此来同步画面和资源状态。
  • 道具类、城墙类特效消息类:原理与上面大同小异。
  • 相同点
    1. 都是由玩家发出消息类给服务器,服务器端接收到消息类马上转发给其他玩家,以此来同步玩家状态。
    2. 服务器端控制公共资源状态,当检测到公共资源发生变化,如城墙爆炸、坦克爆炸、子弹消失/爆炸等,立即发送消息给所有坦克玩家,以此来同步游戏状态。

7. 数据流轨迹

  1. 具体消息类继承抽象类Msg,实现处理、序列化、反序列化方法。
  2. 自定义协议,经过encoder编码,将具体消息类序列化变成字节数组,以便于发送,加上协议头之后通过channel发送字节数组。
  3. decoder译码,解析协议头,获取到正确的字节数组,根据解析到的消息类型,反序列化字节数组,以此来获取到想要的消息类信息。
  4. 接收到正确的消息类之后,调用消息类的处理方法进一步处理。

8. 整个游戏后端架构

​ 整个后端架构可以看成是一个AFS架构,服务器端看成master节点,客户端看成worker节点,服务器端保存整局游戏的所有状态(如果整局游戏的状态在客户端,很有可能会被外挂修改状态,达到作弊的效果),当数据状态发生改变的时候,将状态发生改变的那一部分数据同步给所有客户端,已达到实时联机的效果;每次当一个游戏玩家发出一个事件,都会通过channel先发送到服务器端,然后通过服务器端对该游戏其他玩家的channel发送事件信息,以便其他玩家能够同步事件。

​ 为什么不用NFS架构?

​ NFS架构设计初衷是为了更好的容错,便于数据恢复;而AFS设计初衷是为了更多的用户并发使用,保证更好的实时性。

9. 坦克大战游戏服务器理解

​ 游戏的服务器有很多种,坦克大战使用的服务器是最简单的一种方式,简单且资源消耗少,即收到消息就直接全部转发给其他玩家。

10. 为什么要禁用Nagle算法

​ TCP为了实现增加传输效率会使用Nagle算法,而Nagle算法在游戏服务器领域是被禁用的;原因是Nagle算法如果传输的协议包过小,会积累好几个数据包一起发送,而在游戏中会造成信息的延迟,导致数据不同步。

11. 整个游戏服务器整体划分

  • 整局游戏的全部资源状态由服务器端保存,游戏的资源分为公共资源和玩家资源两部分。
  • 公共资源为电脑(人机)敌人坦克和城墙、道具等,由服务器端控制并检测其状态,当状态发生改变发送对应消息类给所有玩家,同步服务器和所有玩家的画面资源数据。
  • 玩家资源部分由玩家自己控制,产生的动作包装成消息类发送给服务器,服务器接收到后马上转发给其他玩家,之后服务器端进行接收到的消息逻辑处理,处理结果也转发给所有玩家。
  • 实现公共资源和玩家资源的数据信息同步。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程哥哥吖

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值