⭐⭐⭐ Spring Boot 项目实战 ⭐⭐⭐ Spring Cloud 项目实战
《Dubbo 实现原理与源码解析 —— 精品合集》 《Netty 实现原理与源码解析 —— 精品合集》
《Spring 实现原理与源码解析 —— 精品合集》 《MyBatis 实现原理与源码解析 —— 精品合集》
《Spring MVC 实现原理与源码解析 —— 精品合集》 《数据库实体设计合集》
《Spring Boot 实现原理与源码解析 —— 精品合集》 《Java 面试题 + Java 学习指南》

摘要: 原创出处 https://my.oschina.net/u/1859679/blog/842513 「wier」欢迎转载,保留摘要,谢谢!


🙂🙂🙂关注**微信公众号:【芋道源码】**有福利:

  1. RocketMQ / MyCAT / Sharding-JDBC 所有源码分析文章列表
  2. RocketMQ / MyCAT / Sharding-JDBC 中文注释源码 GitHub 地址
  3. 您对于源码的疑问每条留言将得到认真回复。甚至不知道如何读源码也可以请教噢
  4. 新的源码解析文章实时收到通知。每周更新一篇左右
  5. 认真的源码交流微信群。

img

本篇是游戏开发系列第一篇,如若你有兴趣,请持续关注,后期会持续更新。其他文章列表如下:

游戏开发—协议设计

游戏开发—协议-protobuf

游戏开发-协议-protobuf原理详解

通俗地说,协议就是通信双方能够理解的一种数据格式。维基百科这么定义网络协议:

网络协议为计算机网络中进行数据交换而建立的规则、标准或约定的集合。

协议设计包含三要素:

语法:语法是用户数据与控制信息的结构与格式,以及数据出现的顺序。

语义:解释控制信息每个部分的意义。它规定了需要发出何种控制信息,以及完成的动作与做出什么样的响应。

时序:时序是对事件发生顺序的详细说明

也就是说,语义表示要做什么,语法表示要怎么做,时序表示做的顺序。我们要基于此来设计我的协议。

通常游戏有一些特殊性,比如流量要尽量的少,安全性要求更高,以及对平台支持足够多等等。这一切的需求就要求游戏协议设计,尽量简单、通用,以及代码层上易扩展、解析效率足够高等特点。

基于此,我需要从以下几个层次来考虑游戏协议的设计方案。

知识图谱

因为知识点比较多,建议先读知识图谱,对整体结构有一个清晰的综括。

img

协议三个层次

应用层

应用层主要是常用是解析方式定义和解析,主要的选型,主要是看你基于什么需求了,适用于实际需求就好。我们常用的协议类型,主要有这两种:文本协议、二进制协议

1、文本协议:

文本协议设计的目的就是方便人们理解,读懂。如常见的http协议,一般的常见http协议如下:

GET/sample.Jsp HTTP/1.1
Accept:image/gif.image/jpeg,*/*
Accept-Language:zh-cn
Connection:Keep-Alive
Host:localhost
User-Agent:Mozila/4.0(compatible;MSIE5.01;Window NT5.0)
Accept-Encoding:gzip,deflate
username=test&password=1234

这种格式非常贴近我们的文字描述,方便阅读,而且目前HTTP也是客户端浏览器或其他程序与Web服务器之间的应用层通信协议,适用非常广泛。但你也看到,有时候基于一个很简单应答,就要带上很多其他的头信息,这对于对流量有要求的游戏应用来说,还是很浪费的。

优点

1、通用,适用广泛

2、方便理解,可读性好

缺点:

1、基于行读,解析效率一般

2、携带附带信息过多,传输的效率低下

3、无状态,服务器不知道客户端的状态,必须基于客户端的请求来回应,实时性低

4、很难嵌入其他数据,对二进制支持差

如果你的游戏对实时性要求不高,而且对流量要求不也是太高,文本协议也是个不错的方式。一般短连接游戏多适用这个。

2、二进制协议

二进制协议就是一串字节流,是一个典型的Ip协议,一般通常包括消息头(header)和变长的消息体(body),消息头的长度固定,消息体长度不固定,包含主要的内容主体。一般消息头会包含消息体的长度,这样就能基于头信息从数据流中解析出一个完整的二机制消息了。

一般的格式如下:

img

我们看到head部分定义包含:

cmd:命令字

sign:验证串

content-leg:消息体长度

HeaderCRC:头验证(不是必须)

其中命令字是双方协议文档中规定好的,比如0x01表示登录,0x02表示注册等等,这些就是一个命令号。

sign是一个验证字符串,对消息体数据进行一定加密验证,保证数据安全。

content-leg是本次消息体的长度。

body部分,比如我们如下定义:

message:login{

string username;

int64 passwoard;

}

我们看到,因为字段的数据类型有定义,顺序也有定义(第一个是string,第二个是int64),整个二进制流读取的的时候,基于顺序读取就可以很快的取出了。

优点

1、没有冗余字段,传输高效,耗费流量小

2、解析速度快,基于基础数据类型操作

缺点:

1、可读性差,不利于调试

2、扩展性差,对复杂数据结构支持不够

如果你的游戏,对实时性要求比较高,流量有要求,用二进制比较好,一般大型多人网游,使用二进制协议来设计。

3、数据格式

以上我们看到了两种协议类型,但对于消息体的解析介绍很少,消息体的格式决定了的他的语义和时序,格式不同数据的序列化和反序列化也是不同。比如message:login,你可以基于json来定义,也可以基于xml来定义,定义不同解析方式也各不相同。

一般的消息体格式主要有以下几种:json、protocolBuff、xml、自定义

json

json 是一种轻量级的数据交换格式,互联网应用的很广泛了。常用的框架也很多,推荐fastJson,解析速度还是不错的。json的好处是,开源,格式统一,解析速度也还可以。缺点就是会有一些冗余字符,不够简洁。

protocolBuff

protocolBuff是是google提供的一个开源序列化框架,类似于XML,JSON这样的数据表示语言。但是比这些占用空间都小,没有冗余字段。而且好处是灵活,解析速度快,易于开发(基于配置自动生成代码),可支持语言也比较多。一条消息数据,用protobuf序列化后的大小是json的10分之一,xml格式的20分之一,是二进制序列化的10分之一

xml

不多解释了,大家都用有过,强烈不建议使用这种,除了无效字符过多(标签),而且解析效率比上面两种都是很低的。

自定义

自己定义就是自己定义解析方式,比如通过文档定义好一个消息的结构,第一个字段是什么类型,第二个字段什么类型...等等,基于此自己写工具解析。好处是对外协议不透明,解析效率和传送效率都还不错,缺点就是开发难度高,不容易维护。

各种格式优缺点如下:

img

安全层

游戏通信,安全也很重要,不然协议被破解,用户刷资源,整个游戏的平衡性就被破坏了,轻者影响其他玩家体验,重则游戏直接被废。

一般的安全处理就是对协议进行加密。一般有以下几种:

1、常规加密

采用对称加密或者hash加密来对消息内容进行加密,两端采用同一种加密算法,基于同一个密钥对消息体进行加密换算,以此来查看数据是否一致。

密钥可以用户登录的时候获取一次。还有一种是基于每个用户密钥不同,以此防止密钥泄露大范围影响全服玩家。

2、动态加密

动态加密,可以提前设置一个私有密钥库,里面包含一定数量的密钥,每次客户端请求的时候,基于协议号来设计一个算法获取其中一个密钥。每个协议的密钥都是在协议到达的时候时时获取的,这样即便某一个协议的密钥被破解,对其他协议依然无效。

3、其他

采用非对称加密,或者加盐处理。非对称加密速度太慢了,不建议。

传送层

考虑服务端的承载成本,以及手机游戏上网络环境差,原则上UDP是比TCP更适合的方式。但是由于游戏对于数据完整性、安全性要求比较高,采用TCP的又可靠与安全。

目前采用netty作为推送服务器的也有支持上百万连接的应用了,tcp这块性能对于一般游戏支持足够了。长链接游戏多采用分区分服来应对高并发压力,短链接多采用分布式来应对。

一些问题

1、字节序

二进制协议中,字节序需要注意,跨语言、平台通信的时候会出现乱码问题。目前的字节序主要有,Little endian和Big endian之分,也就是常说的大头和小头之分。

具体是大头在前还是小头在前,这个和主机的cpu有关系PowerPC系列采用big endian方式存储数据,而x86系列则采用little endian方式存储数据。这个在手机主机上也会出现。

应对方案是:

客户端和服务端强制采用一种字节序,一般采用网络字节序(big endian)

2、浮点数

协议中出现浮点类型要特别注意,浮点类型的传送上面字节序处理OK了,还得注意浮点数的多平台运算不一致问题。

比如游戏中要对寻路、战斗等公式计算,牵扯到浮点数了,有可能前后端算出的不一致,以Arm为例,Arm的浮点数就有软模拟、硬件IEEE-754兼容、SIMD下IEEE-754不兼容三种情况。

此时解决方案,

1、统一一种格式,比如前后端都采用软模拟,或者强制采用硬件IEEE-754(软模拟速度慢)

2、转换为定点数,也就是浮点转换为整数(速度快)

文章目录
  1. 1. 知识图谱
  2. 2. 协议三个层次
    1. 2.1. 应用层
      1. 2.1.1. 1、文本协议:
      2. 2.1.2. 2、二进制协议
      3. 2.1.3. 3、数据格式
    2. 2.2. 安全层
      1. 2.2.1. 1、常规加密
      2. 2.2.2. 2、动态加密
      3. 2.2.3. 3、其他
    3. 2.3. 传送层
  3. 3. 一些问题
    1. 3.0.1. 1、字节序
    2. 3.0.2. 2、浮点数