FPS游戏漫谈优化包体传输

2024-02-26 09:44

本文主要是介绍FPS游戏漫谈优化包体传输,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

在游戏服务器的部署环境中,机房的网络带宽都是有限制的。如果通信传输的数据总量太大,会挤占带宽甚至达到带宽上限,影响正常消息发送。另外,如果包体太大,在弱网环境下的通信质量会变差,更容易发生丢包重传和延迟,而且大包对于截包和查找问题也不方便。因此我们需要对消息通信做优化,减少包体的大小和数量,进而减小传输的数据总量。

缩减包体大小
我们很容易理解包体太大对网络通信造成的负面影响。因为一个完整的数据包在通信协议底层也是拆成多个小包发送,在弱网环境下,每个小包都有可能发生丢包重传和延迟,叠加起来会让整个完整数据包也更容易出现问题。另外有实际经历的人会很理解从一大堆冗余数据里查找目标字段时的痛苦。

缩减包体大小的第一个方法是只传必要字段。

首先是使用前端静态表。策划配置的数据一般称为静态表,与存储玩家数据的动态表不同,静态表是只读不可修改的。建议对静态表的数据归类,数值类的放在服务端,显示类的放在客户端,这样好处是很多数据前端可以直接从前端静态表读取,不再依赖后端传输,后端通常只需要传一个id作为索引。

对于前后端静态数据如何划分是一个值得权衡的问题。通常来说,衡量的标准有两个维度:与前后端业务的相关性,以及该数据占用空间的大小。例如,数值类的数据与服务端计算强相关,因此适合放在服务端;而描述性的文字占用字节多,不宜通过服务端传输,因此放在客户端;图片和动画资源路径类的数据与客户端业务强相关,也放在客户端。

不过有时候前后端静态数据的划分界限并不那么清晰,这时候还需要结合其他要素做判断。例如,一个数值类的数据前后端都用到了,那么是否还需要放在回包消息中由后端传输呢?我们可以提前预判这个数据在将来变化的可能性大小,如果不太可能变化,那么就让前端直接从前端静态表中读取;反之,如果变化可能性很大,那么还是让前端从后端回包中获取该数据。这样做的好处是,模块上线后一旦需要数值调整,可以只需要后端对静态表做一次热更新,而前端不需要发额外的热更新,前者比后者对玩家的影响更小。

我们可以将前端静态表设计为后端静态表数据的超集,这样在选择本地读取还是后端传输时有更大的灵活性。

其次是优化消息结构体,减少冗余字段。例如下面的json数据用于描述玩家的功能列表中有哪些已开启:

“functionList”: [
{
“functionId”: 1
“isOpen”: true
},
{
“fuctionId”: 2
“isOpen”: false
},

]
1
2
3
4
5
6
7
8
9
10
11
可以将已开启功能的id直接放到一个列表中,精简为如下结构:

“openFunctionList”: [
1, 3, 4, …
]
1
2
3
任何一个合格的游戏服务器程序员都应该追求简单有效的协议模型。

缩减包体大小的第二个方法是对传输数据做压缩。

一般建议对传输数据开启压缩。常用的压缩算法有Gzip、LZ4、Deflate等。就拿最常见的Gzip来说,通常情况下它可以将json数据压缩到原来的1/3到1/2大小,用时仅为毫秒级别。不过压缩率也受到数据大小和数据内容的影响。如果原始数据中的内容重复率很高,数据量较大,那么压缩效果会更好,因为Gzip底层是基于LZ77算法和霍夫曼编码,对重复率高的内容做编码上的优化。

注意,某些二进制通信协议(如Msgpack)本身已对数据做了压缩,那么不要重复做压缩了,重复压缩并不能继续减小包体大小,反而会带来额外的性能开销。

减少推送消息的数量
这是从另一个维度减小传输数据总量。

首先是只推送给必要的对象。推送范围的判断有时候很容易,因为有时范围是固定的,例如一个游戏中的聊天室,每个玩家加入聊天室就默认进入了一个推送消息组,所有的聊天消息都会实时推送到这个消息组里的每个人。通常我们不提倡设立一个超大的聊天室,因为聊天消息的数量与参与人数是O(n^2)的关系,当人数增加时,聊天消息数量会迅速增加直至爆炸。

推送范围有时候又是灵活多变的,典型的例如一个MMORPG中的超大地图上的消息推送,这时就要用到通常所说的AOI算法,只推送给当前对象周围一定范围内的玩家。常用的AOI算法就是基于九宫格模型,还有的游戏会根据业务特点做模型优化,例如我曾经分享过重返帝国使用的梯形模型。
在这里插入图片描述

其次是降低推送的频率。例如,在重返帝国的游戏中,大地图上军队的血量并不需要在每次变化时都推送,可以每隔一小段时间做一次推送,这么细节的内容即使减少推送频率,也不会对玩家体验有明显的变化。降低推送频率的做法也叫推送裁剪。

对包体大小的权衡
要注意的是,包体并非越小越好,必要时还需要合并小包。在笔者的上一篇文章中,我们讲过大量小包的出现会降低网络带宽的利用率,同时导致弱网环境下的传输质量变差。针对这种情况,我们在不影响客户端表现的前提下,在业务层做多个小包的合并。例如,一个由服务端驱动的战斗一帧内向客户端推送了如下三条战报:

A|move|timestamp
B|att|C|timestamp
C|die|timestamp
1
2
3
原本是每产生一条新战报都推送,我们可以优化成服务器运行一帧后再合并推送:

A|move;B|att|C;C|die;timestamp
1
由于客户端也是逐帧渲染,原本一帧以内不同时刻到达客户端的小包实际也是在帧末统一处理和渲染,所以这样的改动不会对玩家体验有任何影响,但是网络传输的效率得到显著提升。

有时候我们也需要分拆大包。例如,在玩家登录游戏时,通常需要向客户端传递大量数据,有人会选择把这些数据全部放在一个接口中,例如:

登录大接口:
玩家基本信息(名字、等级、经验)
聊天历史消息
主城信息
好友信息
1
2
3
4
5
但是我们有充分理由不这么做,而是按功能拆分成多个接口,登录时依次调用它们:

接口一:玩家基本信息(名字、等级、经验)
接口二:聊天历史消息
接口三:主城信息
接口四:好友信息
1
2
3
4
因为大接口有如下四个缺点:

延迟更高,弱网环境下接口超时情况更多。
查看分析回包数据困难。
接口功能定位模糊,复用成本高。
更容易出错,出错时会卡住关键逻辑(登录)。
小结
总之,优化包体传输对于减小带宽占用、提升通信质量都有明显的好处。我们应该从缩减包体大小、减少推送消息数量两个角度做优化。对于包体大小要做适当的权衡,对于大量小包我们需要做必要的合并,而对于大接口我们应该做合理分拆,让每个接口独立做专门的事情。
————————————————

这篇关于FPS游戏漫谈优化包体传输的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/748449

相关文章

Oracle查询优化之高效实现仅查询前10条记录的方法与实践

《Oracle查询优化之高效实现仅查询前10条记录的方法与实践》:本文主要介绍Oracle查询优化之高效实现仅查询前10条记录的相关资料,包括使用ROWNUM、ROW_NUMBER()函数、FET... 目录1. 使用 ROWNUM 查询2. 使用 ROW_NUMBER() 函数3. 使用 FETCH FI

C#使用HttpClient进行Post请求出现超时问题的解决及优化

《C#使用HttpClient进行Post请求出现超时问题的解决及优化》最近我的控制台程序发现有时候总是出现请求超时等问题,通常好几分钟最多只有3-4个请求,在使用apipost发现并发10个5分钟也... 目录优化结论单例HttpClient连接池耗尽和并发并发异步最终优化后优化结论我直接上优化结论吧,

Java内存泄漏问题的排查、优化与最佳实践

《Java内存泄漏问题的排查、优化与最佳实践》在Java开发中,内存泄漏是一个常见且令人头疼的问题,内存泄漏指的是程序在运行过程中,已经不再使用的对象没有被及时释放,从而导致内存占用不断增加,最终... 目录引言1. 什么是内存泄漏?常见的内存泄漏情况2. 如何排查 Java 中的内存泄漏?2.1 使用 J

MySQL不使用子查询的原因及优化案例

《MySQL不使用子查询的原因及优化案例》对于mysql,不推荐使用子查询,效率太差,执行子查询时,MYSQL需要创建临时表,查询完毕后再删除这些临时表,所以,子查询的速度会受到一定的影响,本文给大家... 目录不推荐使用子查询和JOIN的原因解决方案优化案例案例1:查询所有有库存的商品信息案例2:使用EX

MySQL中my.ini文件的基础配置和优化配置方式

《MySQL中my.ini文件的基础配置和优化配置方式》文章讨论了数据库异步同步的优化思路,包括三个主要方面:幂等性、时序和延迟,作者还分享了MySQL配置文件的优化经验,并鼓励读者提供支持... 目录mysql my.ini文件的配置和优化配置优化思路MySQL配置文件优化总结MySQL my.ini文件

正则表达式高级应用与性能优化记录

《正则表达式高级应用与性能优化记录》本文介绍了正则表达式的高级应用和性能优化技巧,包括文本拆分、合并、XML/HTML解析、数据分析、以及性能优化方法,通过这些技巧,可以更高效地利用正则表达式进行复杂... 目录第6章:正则表达式的高级应用6.1 模式匹配与文本处理6.1.1 文本拆分6.1.2 文本合并6

Python开发围棋游戏的实例代码(实现全部功能)

《Python开发围棋游戏的实例代码(实现全部功能)》围棋是一种古老而复杂的策略棋类游戏,起源于中国,已有超过2500年的历史,本文介绍了如何用Python开发一个简单的围棋游戏,实例代码涵盖了游戏的... 目录1. 围棋游戏概述1.1 游戏规则1.2 游戏设计思路2. 环境准备3. 创建棋盘3.1 棋盘类

Vue3 的 shallowRef 和 shallowReactive:优化性能

大家对 Vue3 的 ref 和 reactive 都很熟悉,那么对 shallowRef 和 shallowReactive 是否了解呢? 在编程和数据结构中,“shallow”(浅层)通常指对数据结构的最外层进行操作,而不递归地处理其内部或嵌套的数据。这种处理方式关注的是数据结构的第一层属性或元素,而忽略更深层次的嵌套内容。 1. 浅层与深层的对比 1.1 浅层(Shallow) 定义

HDFS—存储优化(纠删码)

纠删码原理 HDFS 默认情况下,一个文件有3个副本,这样提高了数据的可靠性,但也带来了2倍的冗余开销。 Hadoop3.x 引入了纠删码,采用计算的方式,可以节省约50%左右的存储空间。 此种方式节约了空间,但是会增加 cpu 的计算。 纠删码策略是给具体一个路径设置。所有往此路径下存储的文件,都会执行此策略。 默认只开启对 RS-6-3-1024k

使用opencv优化图片(画面变清晰)

文章目录 需求影响照片清晰度的因素 实现降噪测试代码 锐化空间锐化Unsharp Masking频率域锐化对比测试 对比度增强常用算法对比测试 需求 对图像进行优化,使其看起来更清晰,同时保持尺寸不变,通常涉及到图像处理技术如锐化、降噪、对比度增强等 影响照片清晰度的因素 影响照片清晰度的因素有很多,主要可以从以下几个方面来分析 1. 拍摄设备 相机传感器:相机传