一、什么是丢包?
网络传输数据时,数据会被切成一个个小块,叫数据包。
你的手机 服务器 ┌────┐ 包1 ──────────────────────▶ ┌────┐ │ │ 包2 ──────────────────────▶ │ │ │ │ 包3 ─────────── ✗ 丢了 │ │ │ │ 包4 ──────────────────────▶ │ │ └────┘ └────┘丢包:数据包发出去了,但在路上丢了,对方没收到。
丢包率:丢掉的包占发送总数的比例。
丢包率 = 丢失的包数 ÷ 发送的包数 × 100% 发了 100 个,收到 97 个 → 丢包率 3%二、为什么会丢包?
| 原因 | 说明 | 典型场景 |
|---|---|---|
| 无线信号差 | 信号受干扰,数据传错被丢弃 | WiFi 隔了几堵墙、地铁里 |
| 网络拥堵 | 路由器缓存满了,新来的包直接扔掉 | 晚高峰、家里有人在下载 |
| 切换网络 | WiFi 和 4G/5G 之间切换的瞬间 | 走出家门 |
| 设备性能 | 路由器或服务器处理不过来 | 便宜路由器、服务器负载高 |
| 距离远 | 经过的节点越多,越容易出问题 | 国内玩家连海外服务器 |
特点:丢包常常是“一串一串”的,而不是均匀分布。比如信号突然变差,可能连续丢 10 个包,然后又恢复正常。
三、丢包率多少算正常?
| 丢包率 | 体验 |
|---|---|
| 0% ~ 1% | 很好,基本无感 |
| 1% ~ 3% | 偶尔卡一下,大部分游戏能接受 |
| 3% ~ 5% | 明显卡顿、角色瞬移 |
| 5% ~ 10% | 很难玩,竞技游戏基本无法正常游戏 |
| 10% 以上 | 频繁断线 |
有线网络通常接近 0%;手机 4G/WiFi 一般在 0~2%,信号差时可能超过 10%。
四、丢包、延迟、抖动:三个容易混淆的概念
延迟(Ping):包从发出到收到要多久 → 例如 50ms 丢包: 包有没有到 → 例如 2% 没到 抖动(Jitter):每个包的延迟是否稳定 → 例如忽快忽慢用快递比喻:
延迟:快递要 2 天才到 丢包:100 个快递丢了 3 个 抖动:有的 1 天到,有的 5 天到,很不稳定丢包往往会变成延迟:如果用 TCP,丢了的包要重发,等重发的这段时间画面就卡住了。
五、丢包在游戏里表现成什么样?
丢了玩家操作包 → 按了技能没反应,或者延迟释放 丢了位置同步包 → 别的角色突然瞬移、原地抽搐 丢了状态包 → 血量、分数显示不对,过一会儿突然跳变 连续大量丢包 → 画面冻结,然后“快进”,或直接断线六、TCP 和 UDP:丢包时的两种处理方式
TCP:保证送到,但会卡
发送:包1 包2 包3 包4 包5 收到:包1 包2 ✗ 包4 包5 TCP 的做法:包3 没到,包4、包5 先扣着不给游戏 等包3 重新发过来,再按顺序一起交给游戏 时间线: ──包1──包2──[等待重发包3......]──包3包4包5一起到──▶ ↑ 游戏在这里卡住了这叫队头阻塞:一个包丢了,后面所有包都要等。
UDP:不保证送到,但不会等
发送:包1 包2 包3 包4 包5 收到:包1 包2 ✗ 包4 包5 UDP 的做法:包3 丢了就丢了,包4、包5 立刻交给游戏 ──包1──包2──包4──包5──▶ 不卡,但包3 的内容没了游戏怎么选?
| 游戏类型 | 常用协议 | 原因 |
|---|---|---|
| 回合制、卡牌、棋类 | TCP(WebSocket) | 每一步都不能丢,慢一点没关系 |
| MMO、休闲联网 | TCP 或混合 | 实时性要求中等 |
| FPS、MOBA、格斗、赛车 | UDP | 位置每秒更新几十次,旧数据丢了也没用,最新的才重要 |
关键思想:位置信息是“过时就作废”的。丢了第 3 帧的位置,等重发回来时第 6 帧都到了,重发的旧数据已经没意义了。
七、游戏用 UDP 时,怎么对付丢包?
UDP 本身不管丢包,游戏要根据数据的重要程度分别处理。
方法 1:数据分类
不怕丢的数据(直接用最新的): 角色位置、朝向、动画状态 一定不能丢的数据(需要确认 + 重发): 释放技能、捡道具、扣血、聊天消息、结算很多网络库(如 KCP、ENet、Unity Netcode)都提供“可靠通道”和“不可靠通道”,发送时选择即可。
方法 2:确认与重发(用于重要数据)
客户端:发送「释放技能 #105」 服务器:收到后回复「确认收到 #105」 客户端:如果 100ms 内没收到确认 → 重发一次 服务器:根据编号 #105 去重,避免技能放两次方法 3:冗余发送(最常用于玩家操作)
每个包里同时带上最近几帧的操作:
包 10:[操作10, 操作9, 操作8] 包 11:[操作11, 操作10, 操作9] 包 12:[操作12, 操作11, 操作10] 即使包 11 丢了,包 12 里也有操作 11 ✓操作数据很小,多带几帧几乎不增加流量,却能抵抗连续丢 1~2 个包。
方法 4:插值(让别人的角色移动平滑)
客户端故意晚一点点显示其他玩家,在收到的两个位置之间平滑过渡:
收到位置: A(第1帧) [第2帧丢了] C(第3帧) 不插值: A ───────────────瞬移──▶ C 插值: A ── 平滑移动 ── B' ──▶ C (B' 是算出来的)代价是增加一点显示延迟(通常 50~100ms)。
方法 5:外推 / 预测
如果迟迟收不到新位置,就按角色之前的速度和方向继续往前走:
最后收到:在 (10, 0),向右每秒移动 5 没收到新数据 → 0.1 秒后猜测在 (10.5, 0) 收到真实数据 → 如果有偏差,平滑拉回去自己操控的角色则用客户端预测:按下按键立刻在本地移动,不等服务器确认,服务器结果回来后再校正。
方法 6:快照差异 + 确认
服务器只发送“和客户端上次确认的状态相比,变化了什么”。如果某个包丢了,客户端没确认,下次就以更早的确认状态为基准重新算差异,自动补上丢失的内容。
八、怎么测量丢包率?
用命令行测网络本身
# Windows:连续发 100 个包ping-n100服务器地址# Mac / Linuxping-c100服务器地址结果末尾会显示:
已发送 = 100,已接收 = 97,丢失 = 3(3% 丢失)在游戏里自己统计
给每个包加一个递增序号,接收方检查序号是否连续:
收到序号:1, 2, 3, 5, 6, 9, 10 缺少:4, 7, 8 丢包率 = 3 ÷ 10 = 30%// 简单示意intexpectedSeq=0;intreceived=0,lost=0;voidOnPacket(intseq){if(seq>expectedSeq){lost+=seq-expectedSeq;// 中间跳过的都算丢失}if(seq>=expectedSeq){expectedSeq=seq+1;}received++;}floatLossRate=>(float)lost/(lost+received);很多游戏会在界面角落显示 Ping 和丢包率,或在丢包高时显示一个“网络不稳定”的图标。
九、开发时怎么模拟丢包?
开发时自己的网络通常很好,必须人为制造丢包来测试游戏表现:
| 工具 | 平台 | 说明 |
|---|---|---|
| Clumsy | Windows | 免费,可设置丢包率、延迟、乱序 |
| Network Link Conditioner | Mac / iPhone | 苹果官方工具,iPhone 在“开发者”设置里可直接开启 |
| tc netem | Linux | 服务器端常用,例如tc qdisc add dev eth0 root netem loss 5% |
| Android 开发者选项 / 模拟器 | Android | 模拟器可设置网络状况 |
| 引擎自带 | Unity Netcode、Mirror、Photon 等 | 网络组件里通常有模拟丢包和延迟的选项 |
建议测试的情况:
1. 丢包 2%、延迟 50ms → 普通网络,应该流畅 2. 丢包 5%、延迟 150ms → 较差网络,应该能玩 3. 丢包 15%、延迟 300ms → 极差网络,不应崩溃或卡死 4. 突然 100% 丢包 3 秒 → 模拟进电梯,检查能否自动恢复总结
1. 丢包率 = 丢失的包 ÷ 发送的包,1% 以下很好,5% 以上明显卡顿 2. 丢包主要来自无线信号差、网络拥堵、切换网络 3. TCP 会重发丢失的包,但会卡住后续数据 UDP 不重发,不卡,但要游戏自己处理丢失 4. 实时游戏常用 UDP,并按数据重要性处理: - 位置等:只用最新的 + 插值 / 预测 - 技能、道具等:确认 + 重发 - 玩家操作:冗余发送最近几帧 5. 开发时一定要用工具模拟丢包,测试弱网下的表现一句话:丢包无法避免,好的网络游戏不是不丢包,而是丢了包玩家也感觉不出来。