Unity 游戏网络基础:从 TCP、UDP 到 HTTP、TLS 与 Best HTTP
本文结合实际项目的实际配置,梳理 HTTP、TCP、UDP、TLS、Keep-Alive、HTTP/2 多路复用以及 Best HTTP 之间的关系。
一、先理解网络协议的层级
HTTP、TCP、UDP 并不是三个平级、互相替代的协议。
可以把一次网络请求理解成寄快递:
- HTTP:规定包裹中内容的格式
- TLS:给包裹上锁并验证收件方身份
- TCP/UDP:决定包裹怎么运输
- IP:负责根据地址找到目标设备
常见协议组合如下:
text
HTTP/1.1 → TLS → TCP → IP
HTTP/2 → TLS → TCP → IP
HTTP/3 → QUIC → UDP → IP
使用 TLS 的 HTTP 就是 HTTPS:
text
HTTPS = HTTP + TLS
二、TCP 和 UDP 有什么区别
TCP 和 UDP 都是传输层协议,负责在设备之间传输数据,但设计目标不同。
| 对比项 | TCP | UDP |
|---|---|---|
| 是否建立连接 | 是 | 否 |
| 是否保证送达 | 是 | 否 |
| 是否保证顺序 | 是 | 否 |
| 丢包处理 | 自动重传 | 默认不重传 |
| 传输开销 | 相对较高 | 较低 |
| 延迟 | 可能因重传增加 | 通常更低 |
| 适合场景 | 登录、支付、背包、资源下载 | 实时位置、语音、直播 |
TCP:可靠优先
如果发送:
text
A → B → C
其中 B 丢失,TCP 会重新发送 B,最终应用仍按正确顺序读取:
text
A → B → C
TCP 会提供:
- 可靠传输
- 丢包重传
- 顺序保证
- 流量控制
- 拥塞控制
因此,登录、支付、账号数据、背包数据等不能丢失的信息,通常使用 TCP。
UDP:实时优先
UDP 发送数据后,不保证对方一定收到,也不保证顺序。
发送:
text
A → B → C
对方可能只收到 A → C,也可能以 C → A → B 的顺序收到。
在实时游戏中,玩家上一帧的位置数据如果丢失,可能没有必要等待重传,因为下一帧的新位置更有价值。因此,高频位置同步、语音和视频等场景经常选择 UDP。
应用也可以在 UDP 之上自行实现确认、排序和选择性重传。
三、HTTP 是什么
HTTP 是应用层的请求---响应协议,负责定义客户端和服务器如何表达请求。
例如客户端请求玩家数据:
http
GET /player/info
Authorization: Bearer xxx
服务器返回:
http
HTTP/1.1 200 OK
Content-Type: application/json
{"level": 20}
HTTP 规定了请求地址、GET/POST 等请求方法、Header、状态码以及请求体和响应体。
HTTP 通常不直接负责丢包重传和数据排序,而是依赖下面的 TCP 或 QUIC。
四、TLS 是什么
TLS 全称是 Transport Layer Security,即传输层安全协议,主要解决三个问题:
- 数据加密:即使网络数据被截获,攻击者也无法直接读取账号、密码、Token 和响应内容。
- 身份认证:客户端通过服务器证书确认自己连接的是真实服务器。
- 完整性保护:检测数据是否在传输过程中被修改。
TLS 握手
HTTPS 开始传输业务数据前,需要进行 TLS 握手:
text
客户端声明支持的 TLS 版本和算法
↓
服务器选择算法并返回证书
↓
客户端验证证书与域名
↓
双方协商会话密钥
↓
开始传输加密的 HTTP 数据
TLS 握手需要额外的网络往返和计算,因此频繁重新连接会增加请求延迟。
为什么 HTTPS 不能随便把域名替换成 IP
假设服务器证书属于 api.example.com,如果直接访问 https://1.2.3.4/,可能因访问目标与证书域名不一致而验证失败。
当前项目使用 Best HTTP 的 DNS Host Override:
text
请求地址:https://api.example.com
实际连接:1.2.3.4
证书验证:api.example.com
这样既能切换备用 IP,也能维持正确的 TLS SNI 和证书验证。相关代码位于 Assets/Scripts/Main/SystemService/AccountCenterService.cs。
五、Keep-Alive 是什么
Keep-Alive 表示一次 HTTP 请求完成后,不立即关闭底层 TCP 连接,后续请求继续复用它。
不使用 Keep-Alive
text
TCP 建连 → TLS 握手 → 请求1 → 关闭
TCP 建连 → TLS 握手 → 请求2 → 关闭
TCP 建连 → TLS 握手 → 请求3 → 关闭
使用 Keep-Alive
text
TCP 建连 → TLS 握手 → 请求1 → 请求2 → 请求3
它可以减少 TCP 建连和 TLS 握手次数,降低请求延迟,并减少客户端和服务器开销。
当前项目通过下面的代码开启 HTTP/1.x 连接复用:
csharp
globalSettings.HTTP1ConnectionSettings.TryToReuseConnections = true;
配置位置在 Assets/Scripts/Hotfix/Util/BestHttpSettings.cs。
当前项目的空闲超时
最大空闲时间的计算为:
text
DefaultConnectTimeout + DefaultReadTimeout
= 10 秒 + 5 秒
= 15 秒
因此,一条连接空闲超过 15 秒后,就会被关闭或不再复用。
网络切换、重新登录等场景下,旧连接可能已经失效,所以项目还会主动调用:
csharp
HostManager.RemoveAllIdleConnections();
六、HTTP/1.x 和 HTTP/2 的区别
HTTP/1.x 包括 HTTP/1.0 和 HTTP/1.1,现代项目通常指 HTTP/1.1。
| 对比项 | HTTP/1.1 | HTTP/2 |
|---|---|---|
| 数据格式 | 文本 | 二进制帧 |
| 同一连接并发 | 能力有限 | 支持多路复用 |
| 常用并发方式 | 建立多条连接 | 一条连接承载多个请求 |
| Header | 重复传输较多 | 支持 HPACK 压缩 |
| 调试难度 | 相对简单 | 相对复杂 |
| 兼容性 | 非常成熟 | 依赖网络链路完整支持 |
HTTP/1.1
在常见实现中,一条连接通常处理一个正在进行的请求。为了提高并发量,客户端会建立多条 Keep-Alive 连接:
text
连接1:请求 A
连接2:请求 B
连接3:请求 C
当前项目将同一目标的最大连接数设置为 12:
csharp
globalSettings.HostVariantSettings.MaxConnectionPerVariant = 12;
HTTP/2
HTTP/2 可以在一条 TCP 连接中同时处理多个请求:
text
一条连接:请求 A + 请求 B + 请求 C
它通过多路复用,让不同请求的数据交错传输。
七、什么是多路复用
多路复用就是让多个独立请求共享同一条连接,并且数据可以交错传输。
HTTP/2 会给每个请求分配不同的 Stream ID:
text
Stream 1:请求 A
Stream 3:请求 B
Stream 5:请求 C
一条 TCP 连接上的实际数据可能是:
text
A1 → B1 → C1 → A2 → C2 → B2
接收方根据 Stream ID,把这些数据重新组装成 A、B、C 三个完整响应。
它可以减少 TCP 连接和 TLS 握手次数,让多个请求同时传输,降低大量小请求的延迟。
HTTP/2 仍然存在 TCP 队头阻塞
HTTP/2 解决了 HTTP 层面的请求排队,但所有请求仍共享一条 TCP 连接。如果 TCP 数据包丢失,TCP 必须等待重传,在此期间多个 HTTP/2 请求都可能受到影响。
HTTP/3 改用基于 UDP 的 QUIC,进一步改善了这个问题。
八、为什么项目关闭 HTTP/2
当前项目明确关闭了 HTTP/2:
csharp
globalSettings.HTTP2ConnectionSettings.EnableHTTP2Connections = false;
当前采用的网络策略是:
text
HTTP/1.x
+ Keep-Alive
+ 最多 12 条连接
+ 15 秒空闲超时
HTTP/2 理论性能更好,但实际项目还需要考虑 CDN、代理和网关兼容性、移动网络差异、DNS/IP 容灾、TLS SNI、跨平台稳定性以及线上问题排查难度。
仅凭当前代码只能确认项目主动关闭了 HTTP/2,无法确定最初是否发生过具体线上故障。
九、Best HTTP 是什么
com.tivadar.best.http 是 Unity 的第三方网络库,当前版本为 Best HTTP v3.0.17。
它可以替代或增强 UnityWebRequest,提供:
- HTTP/HTTPS 请求
- HTTP/1.x 和 HTTP/2
- 连接池与 Keep-Alive
- Cookie 管理
- HTTP 本地缓存
- DNS 与代理控制
- TLS 和证书处理
- 请求认证、压缩和流式上传下载
- 网络性能分析
Packages/com.tivadar.best.http/Runtime/Shared/HTTPManager.cs 中的 HTTPManager 是它的全局管理入口,负责初始化、请求调度、缓存、Cookie、连接更新以及退出清理。
十、为什么不用纯 UnityWebRequest
不是因为 UnityWebRequest 完全不能用,而是当前项目需要更细致的网络控制。
Best HTTP 在本项目中的优势主要有:
- 控制 Keep-Alive、连接复用、空闲时间和最大连接数
- 提供统一的 CookieJar 和本地 HTTP 缓存
- 主动移除失效的空闲连接
- 支持域名不变、实际连接备用 IP
- 更容易处理 TLS SNI 和 DNS 容灾
- 让不同平台的网络行为更加统一
当前项目仍然保留 UnityWebRequest 作为后路:
csharp
HttpChannel.UseBestHttp =
string.IsNullOrEmpty(loginExa.useLegacyhttp) ||
loginExa.useLegacyhttp == "0";
默认使用 Best HTTP。如果某个平台或线上版本出现兼容问题,服务端可以通过 useLegacyhttp 切回旧网络实现。
十一、完整关系总结
一次普通的 HTTPS 请求可以理解为:
text
业务数据
↓
HTTP:定义请求和响应格式
↓
TLS:加密数据并验证服务器身份
↓
TCP:保证可靠、有序地传输
↓
IP:将数据送到目标设备
当前项目的主要 HTTP 策略是:
text
Best HTTP
↓
HTTP/1.x
↓
Keep-Alive 连接复用
↓
TLS 加密
↓
TCP 可靠传输
↓
IP 网络
最终可以记住下面几句话:
HTTP 决定数据怎么表达,TCP/UDP 决定数据怎么运输。
TCP 追求可靠和有序,UDP 追求轻量和低延迟。
TLS 负责加密、身份认证和防止篡改。
Keep-Alive 通过复用 TCP/TLS 连接减少重复建连开销。
HTTP/2 通过多路复用,让多个请求共享同一条连接。
Best HTTP 为 Unity 提供了比 UnityWebRequest 更细致的连接、缓存、Cookie、DNS 和 TLS 控制能力。