Unity中的网络

时间:2022-11-17 18:59:33

网络连接

硬件

客户端和服务端通过集线器连接着路由器,路由器连接到互联网服务提供商。


网络协议

TCP

参考链接:​https://www.cnblogs.com/AhuntSun-blog/p/12028636.html​

三次握手:TCP连接的建立

Unity中的网络

Unity中的网络

  • Step 1: 客户端向服务端发送报文
  • Step2: 服务端接收之后结束Listen状态,返回一段报文
  • Step3:客户端接收之后,明确数据传输是正常的;返回一段TCP报文

TCP协议不一定是客户端先发出的,服务端也可以先发出。

涉及到的字段
  • Seq:序号,32位,发起方发送数据的时候对此进行标记
  • Ack:确认号,32位,只有为1的时候,确认序号字段才有效

Unity中的网络


意义

为了防止服务器端开启一些无用的连接增加服务器开销以及防止已失效的连接请求报文段突然又传送到了服务端,因而产生错误。

只有两次的话无法确认客户端收到了服务端的消息,如果四次以上,就多做了无谓的确认。

只有两次的一个错误case:如果之前有一个包阻塞之后又建立起了连接,那么服务端就会认为是新发过来的包,从而造成客户端和服务端的状态不一致。

Unity中的网络

四次挥手:TCP连接的解除

Unity中的网络

Unity中的网络

  • Step1:客户端关闭ESTABLISHED状态,向服务端发送一段TCP报文
  • Step2:服务端接收到客户端发出的报文之后,确认了客户端想释放连接;服务器通知应用进程关闭ESTABLISHED状态,进入Close-Wait状态(半关闭状态),返回一段TCP报文
  • Step3:服务端经过close-await阶段之后,做好了释放连接的准备,再次向服务端发出一段TCP报文
  • Step4:客户端收到服务端的报文之后,结束fin-wait2阶段,进入Time-Wait阶段;向服务端发出TCP报文:
  • ACK:标记接收到服务器准备好释放连接的信号
  • 然后客户端在Time-Wait阶段等待2MSL
  • 服务端收到报文之后,结束LAST-ACK阶段,进入Closed阶段。服务端的连接正式关闭
  • 客户端等待玩2MSL之后,结束Time-Wait阶段,进入Closed阶段,由此完成四次挥手。


三次握手 & 四次挥手

(1)为什么是三次和四次?

建立连接时,被动方服务器端结束CLOSED阶段进入“握手”阶段并不需要任何准备,可以直接返回SYN和ACK报文,开始建立连接。

释放连接时,被动方服务器,突然收到主动方客户端释放连接的请求时并不能立即释放连接,因为还有必要的数据需要处理,所以服务器先返回ACK确认收到报文,经过CLOSE-WAIT阶段准备好释放连接之后,才能返回FIN释放连接报文。

(2)四次挥手的时候为什么要等2MSL

客户端最后发送报文之后不能确定服务端能收到,所以会设置一个时长为2MSL的计时器。MSL(Maximum Segment Lifetime)一段TCP报文在传输中的最大生命周期,2MSL即为服务端发出报文和客户端发出ACK确认报文保持有效的最大时长。

1)如果服务端在1MSL的时候没有收到客户端发出的ACK确认报文,会再次向客户端发出FIN报文。此时处于Time-Wait状态的客户端就可以对Fin报文做出回复。

2)保证让迟来的报文段有足够的时间被识别和丢弃。连接结束了,那么网络中延迟报文也应该被丢弃掉,以免影响立刻建立新的连接。

TCP/IP的五个层级

  • 物理层:广电信号的传输
  • 数据链路层:设备之间数据帧的传输和识别。
  • 网络层:地址管理和路由选择。路由器工作的层级。
  • 传输层:负责两台主机之间的数据传输。
  • 应用层:网络编程是在这个层级

数据链路层

传输层

功能

通过各种协议保证建立可靠的数据链路。

是通信子网和资源子网的接口和桥梁。

作用


  • 提供流量控制;
  • 保证报文的正确传输

环境

两个分组交换结点直接通过一条物理信道进行通信。

两个主机和整个子网作为通信信道进行通信

数据

信息帧

报文

稳定性

TCP是稳定的,因为提供了乱序重排、应答确认、报文重传、流量控制等四种机制。

(1)乱序重排:由于网络或者多线程的因素,接收到的数据段可能是乱序的,但是每个TCP报文中都封装了序号,所以重组起来很容易。

(2)应答确认:如果客户端发送了多个数据段,那么服务端接收到的时候只需要在多个数据段的和上加1作为回应报文的确认号就可以了。

(3)报文重传:

超时重传:TCP会根据网络速度的不同调整重传时间(RTO);每发送一个报文就会开始计时,如果超时就会自动的重新发送。

快速重传:如果接收方发送序号为2的报文,表示希望收到序号为2的报文,但是接下来却收到了3、4、5等,那立即再发送序号为2的报文。

(4)流量控制:

发送或者接受数据的时候,都会把数据先放进缓冲区,所以缓冲区的大小就决定了一次能处理的数据的能力。如果处理速度比发送速度慢,就会导致溢出。TCP建立连接的时候客户端和服务端会协商缓冲区window的大小,通过报文中的window字段来进行确认。发送方会根据服务端发回来的报文中的window值来调整每次发多少报文,发送的窗口会向左滑动、大小也会变化,这叫做窗口滑动。 


流量控制、拥塞控制、断线重连

(1)流量控制:TCP中使用滑动窗口机制

目的:让发送的速率不要过快,以至于接收方来不及处理。

原理:利用报文中的window字段来控制窗口,使得发送方的发送窗口小于接收方发回的窗口大小。

Bad case:如果接收方没有缓存使用,发送的报文中window大小为0,那么发送方停止发送;当接收方的缓存恢复,重新发送了窗口非0的报文,如果这个报文丢失,那么发送方会一直锁在window为0的状态。

解决方式:TCP为每一个连接设置一个持续计时(persistence timer),只要有一方收到零窗口的报文,就启动这个计时器,周期性的发送零窗口探测报文段。对方在确认这个报文的时候给出现在的窗口的大小。

(2)拥塞控制

拥塞的发生:路由器溢出,拥塞会导致丢包,但是丢包不一定会引发拥塞。

拥塞控制是快速传输的基础。

拥塞控制算法包括:慢启动法、拥塞避免算法、快速重传算法、快速恢复算法。

(3)断线重连

检测到客户端断线:断开客户端的Socket;重新根据IP和端口号重建新的Socket。

当连接上服务器网关之后,携带Token,向服务器发送重连的协议。


UDP & TCP

共同点:都是工作在传输层的,都是用来传输数据的。

区别:TCP基于连接,UDP是无连接的

Unity中的网络

UDP:

  • 优势:性能损耗小、资源占用少
  • 劣势:可能会丢包,稳定性弱;不提供有序的保证。
  • 适用场景:对于网络的实时性要求高,少量丢包问题可以先忽略的情况;语音、视频直播、域名查询,也可以适用于隧道网络(VPN等)

TCP:

  • 优势:稳定可靠
  • 适用场景:文件传输、电子邮件、网页浏览等

TCP

UDP

连接



可靠性

提供交付保证,丢失的话就会重发

不提供交付保证

数据边界

不保证数据边界

UDP中数据包是单独发送的,只有到达之后才会再次集成。

速度

快,可应用于直播、多人在线游戏等

发送消耗

重量级

轻量级

报头大小

大,报头是20字节

小,报头是8个字节,仅包含:长度、源端口号、目的端口、校验码

拥塞或者流量控制

有流量控制

不进行流量控制

应用场景

状态同步,MMO

帧同步,FPS竞技等


Https

Https是在HTTP基础上用TLS/SSL进行加密之后的加密版本。

Http是在应用层的,基于TCP

(1)安全性:防止传输过程被监听,防止数据被窃取

(2)传输过程:

  • 客户端发起请求,服务端返回证书
  • 客户端对证书进行验证,验证后通过证书中的公钥进行加密,传输到服务端,服务端接收之后通过私钥解密
  • 数据交换:使用对称加密算法进行解密

(3)证书:防止中间人入侵,同时为网站提供身份证明

(4)抓包:会被抓包;如果用户主动授信,可以构建中间人网络,代理软件就可以对传输内容进行jiami(不知道为啥是敏感词)。


端口号

0-1023:知名端口号

1024-65535:操作系统动态分配的端口号:

  • 程序注册端口号:1024-49151
  • 动态私有端口号:49152-65535

大小端

  • ​大端是高字节存放到内存的低地址,小端是高字节存放到内存的高地址​。
  • 目前大多数是小端,少数是大端。


网络同步

状态同步 & 帧同步

帧同步

(1)案例:王者荣耀是帧同步的

(2)定点数:帧同步中为了保证各平台的同步,就必须使用定点数物理库,避免一切需要使用浮点数的计算

(3)反作弊:多人竞技中通过客户端上传关键的游戏数据来找到作弊玩家;人数较少的帧同步可以结算之后服务器再加速跑一遍(刀塔传奇)

(4)预表现

预测

定义:就是将玩家的输入立即应用到本地状态,无需等待服务端的返回。这种情况下当服务端返回之后,我们会看到抖动和拉扯,所以引入一个重要概念:和解

和解

预测状态 = 权威状态+预测输入

  • 权威输入:从服务器接收到的输入
  • 预测输入:客户端发出一个输入,但是还没有得到服务端的返回确认的,也叫做非权威输入。

和解的过程:

  • 状态同步:(1)收到服务端同步来的权威状态;(2)将本地状态设为这个权威状态;(3)在权威状态的基础上,应用当前的所有预测输入
  • 帧同步:(1)收到服务端同步来的权威输入;(2)将本地状态回滚到上一次的权威状态;(3)将权威输入应用到当前的状态,得到这次的权威状态;(4)在权威状态的基础上,应用预测输入

插值

用来平滑过渡


和解

插值

发生的位置

逻辑层

表现层

对象

自己

其他人

(5)逻辑、渲染分离

游戏通常被分为逻辑层和表现层,这两个层最终都是面向数据的。

表现层:游戏画面的显示和用户输入的获取;

逻辑层:定义所有的状态和输入,然后实现状态变更;逻辑层本质上就是一个状态机。

(6)帧同步中不同步的原因

帧同步的过程:客户端计算,通过服务器转发给所有的客户端。服务端是不知道逻辑的,如果客户端运算的时候某一帧的变量不一致,就会滚雪球般的越来越严重。呈现的效果就是,不同的客户端显示的结果都是不一致的。

数值的随机性:因为帧同步中逻辑在客户端进行,不同的客户端得到的随机数值是不一样的,就会得到不同的战斗结果。解决方案是做伪随机算法。

逻辑执行顺序不一致:一些第三方插件的Update是没办法用帧同步去控制的。解决方案:避免使用这些不成熟稳定的三方插件。

数学计算中的精度丢失:主要是指浮点数。解决方案:用定点数代替浮点数。

接收的网络数据不一样:UDP容易出现网络波动。解决方案:对每一个发出的消息做一个自增的编号,根据编号的连续性确定消息的顺序。


网络同步的优化

  • (1)表现优化
  • 差值优化
  • 客户端预测+回滚
  • (2)延迟对抗
  • 延迟补偿
  • 命令缓冲区
  • 是线上对抗延迟
  • (3)丢包对抗
  • TCP不会丢包
  • 冗余UDP数据包
  • (4)带宽优化:目的是减小同步压力
  • 同步对象裁剪
  • 分区、分房间
  • 数据压缩和裁剪
  • 减少遍历以及细粒度的优化
  • (5)帧率优化
  • 提升帧率
  • 保持帧率稳定和匹配
  • 计算压力分担:把一部分计算资源交给客户端来计算,比如物理运算、自动寻路、AI逻辑运算等


逻辑在客户端和服务端的区别

客户端:服务器压力小;但是可能会导致作弊(waigua)

服务端:更好复用,降低了整体的计算量;降低了序列化和反序列化的成本,延迟更低;