多人在线斗地主游戏开发——自定义TCP网络通信协议包格式

    什么叫做通信协议?为什么制定通信协议? 怎么制定通信协议? 不知道大家有没有迷茫过这个问题,反正我是有的,,,

    想我在刚接触网络编程的时候,是linux下用socket懵懵懂懂地按照pdf书籍上的代码敲了个非常简单的C/S架构的 聊天程序,

Client端发一个字符串,服务器接收到打印后,再返回一个字符串,敲完了后,自己运行着这个‘很牛 很高大上’的程序,玩得不亦乐乎,同时脑子里迸发了一大堆的想法,终于会网络编程了,之前写的程序只能在本地运行,现在应该可以利用socket写出网络通信的程序了,我可以把自己写的‘游戏’、‘软件’发给远在他方的朋友,一起联网运行(事实上,想多了,理想是丰满的,现实是异常骨感的)。

      经过了一番思考,动手利用socket写了个简单的发送文件的程序,Client发送FileName至Server, Server收到后返回“OK”,然后Client开始读取文件数据,并send.

      其实这里的Client发送FileName,服务器返回OK,  可以说就是所谓的通信协议了,只不过是简陋得有点可怜的通信协议。

       通信协议,实际上就是一种通信的约定,我发什么数据给你,你根据我发的这个数据,要返回什么数据给我,例如下面这个不是很好的例子:

           

 

       上面就是一个简单登录协议, 开发者在动手敲代码之前,就已经规定了Client会发送哪些数据,服务器要怎样响应数据,如Client 发送‘用户名和密码数据,验证登录’,  Server收到后根据协议,就知道这条指令是什么意思,需要我做什么事情,然后我做完了之后该怎么返回结果给Client, 按照上面定好的协议,Server如果验证成功,则返回B 代表的指令,  如果验证失败,则返回C代表指令,而且只能返回这两者其一,不能返回其他数据, 一般协议之外的其他消息数据应该被程序认为是不合法的数据,无效的数据。

      如果Server返回的是B, 那么Client就知道账户密码正确,登录成功了,如果B的指令数据中含有Hall Server(大厅服务器)的IP和Port的话, Client就知道,它可以连接游戏大厅了

      如果Server返回的是C, 那么Client就知道验证失败了,就会做失败的处理。

      所以,通信协议就是一个约定,一个规定,一份对应的请求和响应指令,我发送什么指令给你,你根据我的指令判断 你需要做什么操作,然后根据协议约定的返回结果的数据格式,返回结果给我,我收到你的返回,根据协议上的约定,我就知道接下来我该怎么去做。

       那到这里了,大家可能想问了,在我不知道什么是通信协议的时候,我就已经在用着了,就像上面发送文件的程序一样,我发个字符串给服务器,服务器给我返回一个字符串就行了,那我就按照这样就可以了,何必要再花时间费脑子去制定一个协议呢?

       那不知道大家在写socket TCP程序的时候,有没有遇到过粘包的问题,那时候我和两个同学,写一个局域网斗地主游戏,在tcp通信的时候,经常会遇到这个问题,当Client有连续发送“OK”、“bige”两条消息给服务器的时候,理想状态是,服务器接收到“OK”,然后做相应处理,然后接收到“bige”,再做相应处理, 而实际上呢,服务器接收到的是“OKbige”, 然后导致服务器不知道这是条什么命令,然后无任何相应,甚至出错。

        socket Tcp是流式地发送数据,没有上一条数据和下一条数据之间的界限,属于是水乳交融,无缝连接的。

        那么该怎么解决连包的问题呢? 

        我们可以通过制定一份通信协议来解决连包问题,同时也大大降低程序通信的混乱性,提升代码可读性和健壮性。

        通过阅读了多个开源游戏服务器的网络通信模块,以及一些文档资料,我大概确定怎样制定一份协议,(我知道这可能不是一份完美的协议格式,可能存在一些问题,如果有何建议的话,恭请不吝指教)如下:

        一条协议数据应该由三部分组成:协议头  + 指令数据 + 校验码

            1)协议头:    必须固定大小为多少字节,例如:

    

            有了协议头后,解析协议数据的时候,先接受10个字节的协议头数据,然后在协议头中解析指令类型,再解析指令数据长度length,然后再读取length个字节的数据,这length个字节的数据就是一条单独的指令,后面还有数据的话,就等下次解析了。

           2)指令数据: Client与Server之间具体的请求响应交互操作

           3)校验码:

                校验码一是校验协议包的完整性,二是校验协议包的合法性,防止有其他人恶意 发送消息给Server,造成Server的资源消耗等

        所以完整的协议格式应该如下(序号可以视情况选择用不用):

       发送方 根据此协议格式组织 协议包,发送给接收方,接收方接收后的解析步骤:

              1)读取10字节协议头, 解析出指令长度len

              2)接着后面读取len个字节的数据,此时,已经读取了len+10字节数据,刚好就是一个完整的协议包

              3)将前len+10-2个字节数据,进行校验算法的校验,生成出两字节的校验位

              4)将生成的校验位与接收到的协议包中的校验位进行比较,如果相同则,指令正确,如果不同,则校验失败,数据异常,可以选择丢掉数据等处理

              5)校验成功后,根据协议包中的指令类型,将指令分发到对应功能的接口模块,进行处理。

        此外,通常情况下,为了防止tcp通信的协议包被抓包破解,泄漏程序的业务流程,造成极大的安全隐患,在发送组织好的协议包之前,还会用加密算法,将指令数据进行加密,然后再发送至接收端,接收端,先进行解密,再效验数据。

 

        网络通信中用到的通信格式,还有Json、XML、谷歌的protobuf等等

 

 

 

 

 

 

 

 

 

 

 

 

 

 

   

  • 3
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
开发一个Java斗地主游戏需要掌握以下技术: 1. Java基础知识:了解Java基本语法和面向对象编程思想。 2. Swing界面开发:使用Swing组件进行游戏界面的设计和实现。 3. 面向对象设计思想和设计模式:使用面向对象的方式设计游戏逻辑,如牌局、玩家、出牌、抢地主等。 4. 网络编程:使用Socket或者Netty进行客户端和服务端之间的通信。 5. 多线程编程:使用多线程技术实现游戏逻辑,如自动出牌、倒计时等。 6. 数据库:使用数据库存储游戏数据,如玩家信息、战绩等。 下面是一个简单的斗地主游戏开发流程: 1. 设计游戏界面,括玩家头像、手牌区域、出牌区域、底牌区域等。 2. 设计游戏逻辑,括洗牌、发牌、抢地主、出牌等。 3. 实现游戏界面和逻辑之间的交互,如点击出牌按钮后,将出牌信息发送给服务端,由服务端进行判断。 4. 实现客户端和服务端之间的通信,如使用Socket或者Netty进行通信。 5. 实现自动出牌、倒计时等功能,使用多线程技术实现。 6. 使用数据库存储游戏数据,如玩家信息、战绩等。 在开发过程中需要注意以下问题: 1. 游戏逻辑需要仔细设计,考虑各种情况,如玩家出牌不符合规则等。 2. 网络通信需要考虑网络延迟和通信安全等问题。 3. 多线程编程需要注意线程安全问题,如使用同步锁等技术保证线程安全。 4. 数据库需要注意数据的一致性和安全性等问题。 以上是一个简单的Java斗地主游戏开发流程,希望对你有所帮助。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

春休夏末

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

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

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

打赏作者

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

抵扣说明:

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

余额充值