Hotdry.
systems-engineering

Quake 自定义 TCP/IP 实现的逆向工程:56k 调制解调器多人游戏的连接建立、数据包封装与不可靠链路的可靠性

逆向工程 Quake 在 56k 调制解调器时代自定义网络协议的设计,焦点在连接建立、数据包结构及在不可靠链路上的可靠性机制,提供工程化参数与监控要点。

Quake 作为 1996 年 id Software 开发的经典第一人称射击游戏,其多人模式在 56k 调制解调器时代实现了革命性的低延迟体验。这得益于其自定义的 “TCP/IP” 实现 —— 实际上是基于 UDP/IP 的 NetChannel 抽象层。该设计针对拨号上网的高延迟和高丢包率,优先确保实时性而非绝对可靠性,避免了传统 TCP 的重传机制带来的额外延迟。逆向工程显示,这种自定义栈聚焦于连接快速建立、紧凑数据包封装,以及在不可靠链路上的智能可靠性补偿,适用于现代低带宽或高丢包场景的游戏网络优化。

首先,理解为什么 Quake 摒弃标准 TCP/IP 而选择 UDP。观点在于:FPS 游戏中,过时信息无价值,重传会放大延迟。在 56k modem 下,TCP 的拥塞控制和确认机制可能导致数百毫秒延迟,而 Quake 需要每帧(约 10ms)更新玩家位置和动作。证据来自源代码审查:引擎使用 UDP 作为传输层,NetChannel 层模拟部分 TCP 功能,如序列化和确认,但仅限于关键命令。Fabien Sanglard 的分析指出,Quake World 引擎(Quake 的多人扩展)明确为互联网设计,UDP 允许丢弃旧包,优先新鲜数据。这在 modem 时代尤为关键,当时平均延迟 100-300ms,丢包率 5-10%。

连接建立过程简洁高效,类似于简化版 TCP 三次握手,但基于 UDP 的无连接特性。客户端发起连接时,发送初始数据报,包括随机 QPort(用于 NAT 穿越)和序列号 0。服务器响应确认包,包含 ACK 序列号和自身序列号,建立双向 NetChannel。整个过程在 1-2 个往返时间内完成(约 200-500ms),远低于 TCP 的 SYN-ACK 机制。证据:源代码中 Netchan_Init 函数初始化序列号和缓冲区,QPort 随机生成以区分 NAT 端口变化(常见于 90 年代路由器)。可落地参数:超时阈值设为 1s(3 次重试),初始序列号随机 32 位整数;监控点:连接成功率 >95%,平均建立时间 <300ms,回滚策略:超时后切换 LAN 模式或单人游戏。

数据包封装采用紧凑的二进制格式,优化 56k modem 的低带宽(约 5-7 KB/s)。每个包头 12 字节:序列号(32 位,含可靠标志位)、ACK 序列号(32 位)、QPort(16 位)和命令负载。负载分为可靠和不可靠命令,可靠命令(如玩家退出或关卡加载)仅允许一个未确认包,存于 reliable_buf 中;不可靠命令(如位置更新)批量打包,无重传。包大小上限 1400 字节,避免路由器分片(MTU 1500)。证据:netchan.c 中的 Netchan_Transmit 函数组装头 + reliable + unreliable,序列号递增确保有序。Huffman 压缩可选用于负载,减少 20-30% 带宽。清单:1. 头结构:序列 (int, MSB 为可靠标志) + ACK (int) + QPort (short);2. 负载:svc_playerinfo (玩家位置、命令持续时间) + svc_packetentities (实体 delta 更新);3. 封装参数:最大负载 1024 字节,序列掩码 0x7F (64 槽循环);监控:包大小分布(目标 <1000 字节),压缩率 >15%。

可靠性机制是设计核心,在不可靠链路上模拟 TCP 的部分功能而无延迟代价。观点:仅对关键事件可靠,非关键丢弃以保持流畅。可靠命令添加至 message_buf,仅当 reliable_buf 空时移入并发送,接收方 ACK 后清空。丢包时,重传 reliable_buf 并附加新不可靠命令,形成 delta 更新。证据:源代码显示,序列号的最高位标志可靠包,接收时若标志位设,清理缓冲;流控仅服务器端,基于客户端 rate 命令跳过更新。针对 modem 丢包,引擎存储 64 最后帧(frames 数组),用 & UPDATE_MASK (63) 循环索引,高效计算延迟(receivedtime - senttime)。可落地参数:可靠阈值 1 个包,ACK 超时 200ms(modem RTT 约 100ms);重传上限 5 次;清单:1. 可靠缓冲:单槽 FIFO,溢出断连;2. Delta 更新:比较旧帧与新帧,仅发变化(位标志前缀);3. 延迟补偿:客户端预测移动,服务器权威校正;监控点:丢包率 <5%,可靠成功率 99%,平均 RTT <250ms,回滚:高丢包 (>10%) 时降级至本地预测。

这种设计在现代仍有借鉴价值,如 QUIC 协议的 UDP 基础。Quake 的自定义栈证明,低带宽环境下,简化可靠性和 delta 压缩可实现可靠多人游戏。实际部署中,参数调优需测试 modem 模拟环境,确保帧率 >30 FPS。

资料来源:Fabien Sanglard 的 Quake 源代码审查(https://fabiensanglard.net/quakeSource/quakeSourceNetWork.php),id Software Quake 源代码 (GitHub)。

查看归档