0

0

UDP 数据传输中发送端丢包是否可能发生?

心靈之曲

心靈之曲

发布时间:2025-12-29 12:44:02

|

229人浏览过

|

来源于php中文网

原创

UDP 数据传输中发送端丢包是否可能发生?

udp 发送调用成功(send() 返回无异常)并不保证数据包真正抵达对端——丢包可发生在发送队列溢出、网卡驱动缓冲区满、中间设备拥塞等任意环节,且完全静默,无异常抛出。

在基于 UDP 实现可靠文件传输时,一个常见误区是认为“只要 send() 调用成功,数据就已发出并大概率可达”。事实并非如此:UDP 的 send() 是非阻塞的“尽力而为”接口,其成功仅表示数据已拷贝至内核发送缓冲区,不承诺任何链路层或网络层的投递保障

丢包可能发生在多个环节,且均不会触发应用层异常:

  • 本地发送队列溢出:当应用层持续高速调用 send(),超出内核 socket 发送缓冲区(SO_SNDBUF)容量时,后续 send() 可能被阻塞(若 socket 为阻塞模式)或直接返回 EAGAIN/EWOULDBLOCK(非阻塞模式);但若缓冲区尚有空间,数据入队即返回成功,而实际在后续协议处理(如 IP 分片、ARP 解析、网卡驱动入队)中仍可能因资源不足被静默丢弃;
  • 网卡驱动或硬件缓冲区饱和:即使内核缓冲区未满,网卡驱动环形缓冲区(TX ring buffer)满载时,底层驱动可能直接丢弃待发送帧,且不向上层反馈;
  • 中间网络设备拥塞路由器、交换机等在队列满时采用尾部丢弃(Tail Drop)或主动队列管理(如 RED),此类丢包对通信双方完全透明;
  • 目标主机接收端丢包:如 UDP 接收缓冲区溢出(SO_RCVBUF 不足)、中断处理延迟、协议栈过载等,同样无通知机制。

✅ 正确应对方式(尤其在实现类 TCP 可靠性机制时):

  • 必须依赖超时重传 + 确认应答(ACK):不能信任 send() 成功即等于对方收到;
  • 为每个数据包分配唯一序列号,并要求 ACK 携带该序号
  • 客户端需维护未确认报文的重传定时器(RTO),超时即重发(建议使用指数退避);
  • 服务端需去重(根据序列号缓存已收包),避免重复写入文件
  • 显式处理 ACK 丢失:由于 ACK 本身也是 UDP 包,它也可能丢失 → 客户端需重传原数据包,服务端需容忍重复 ACK 和重复数据包。

? 示例关键逻辑(伪代码):

phpBIZ
phpBIZ

基于phpBIZ v2.0 中文自由版,主要实现的功能: 会员数据整合: 论坛的用户可无需注册即可以拥有自己在phpBIZ的帐号,注册一个论坛帐号即可同时拥有一个phpBIZ帐号,注册一个phpBIZ帐号同时也会开通一个相应的论坛帐号,因而避免了重复注册 新商品传送至论坛: 商家登陆的每件商品可以选择是否在论坛发帖通知。后台管理员设定传送论坛版块

下载
# 客户端发送与重传逻辑节选
def send_with_retry(seq, data):
    packet = build_udp_packet(seq, data)
    sock.sendto(packet, server_addr)
    start_timer(seq, timeout=1.0)  # 启动重传定时器

def on_ack_received(ack_seq):
    cancel_timer(ack_seq)          # 收到 ACK 则取消对应重传
    if ack_seq == expected_next_ack:
        expected_next_ack += 1     # 推进滑动窗口

⚠️ 注意事项:

  • 不要试图通过 getsockopt(SO_SNDBUF) 或 ioctl(SIOCOUTQ) 监控发送队列来规避丢包——它们仅反映内核缓冲区状态,无法覆盖驱动层及网络路径上的不确定性;
  • 即使在 localhost 测试(如使用教授提供的模拟 Channel 类),也应完整实现超时/重传/去重,因为模拟丢包正是为了验证协议鲁棒性;
  • 实际部署时,建议结合 setsockopt(IPPROTO_IP, IP_TTL, ...) 控制跳数,并启用 SO_KEEPALIVE(虽对 UDP 无效,但提醒你:UDP 本身无连接保活,需自行设计心跳)。

归根结底:UDP 的“不可靠”本质,不仅在于接收端可能收不到,更在于发送端永远无法得知——它是否真的出发了。 因此,所有可靠性保障必须构建在应用层确认机制之上,而非依赖底层传输语义。

相关专题

更多
硬盘接口类型介绍
硬盘接口类型介绍

硬盘接口类型有IDE、SATA、SCSI、Fibre Channel、USB、eSATA、mSATA、PCIe等等。详细介绍:1、IDE接口是一种并行接口,主要用于连接硬盘和光驱等设备,它主要有两种类型:ATA和ATAPI,IDE接口已经逐渐被SATA接口;2、SATA接口是一种串行接口,相较于IDE接口,它具有更高的传输速度、更低的功耗和更小的体积;3、SCSI接口等等。

987

2023.10.19

PHP接口编写教程
PHP接口编写教程

本专题整合了PHP接口编写教程,阅读专题下面的文章了解更多详细内容。

43

2025.10.17

堆和栈的区别
堆和栈的区别

堆和栈的区别:1、内存分配方式不同;2、大小不同;3、数据访问方式不同;4、数据的生命周期。本专题为大家提供堆和栈的区别的相关的文章、下载、课程内容,供大家免费下载体验。

364

2023.07.18

堆和栈区别
堆和栈区别

堆(Heap)和栈(Stack)是计算机中两种常见的内存分配机制。它们在内存管理的方式、分配方式以及使用场景上有很大的区别。本文将详细介绍堆和栈的特点、区别以及各自的使用场景。php中文网给大家带来了相关的教程以及文章欢迎大家前来学习阅读。

558

2023.08.10

Golang channel原理
Golang channel原理

本专题整合了Golang channel通信相关介绍,阅读专题下面的文章了解更多详细内容。

238

2025.11.14

golang channel相关教程
golang channel相关教程

本专题整合了golang处理channel相关教程,阅读专题下面的文章了解更多详细内容。

320

2025.11.17

tcp和udp的区别
tcp和udp的区别

TCP和UDP的区别,在连接性、可靠性、速度和效率、数据报大小以及适用场景等方面。本专题为大家提供tcp和udp的区别的相关的文章、下载、课程内容,供大家免费下载体验。

115

2023.07.25

udp是什么协议
udp是什么协议

UDP是OSI参考模型中一种无连接的传输层协议。本专题为大家带来udp是什么协议的相关文章,免费提供给大家。

265

2023.08.08

ip地址修改教程大全
ip地址修改教程大全

本专题整合了ip地址修改教程大全,阅读下面的文章自行寻找合适的解决教程。

121

2025.12.26

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

相关下载

更多

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Laravel---API接口
Laravel---API接口

共7课时 | 0.6万人学习

ThinkPHP6.x 微实战--十天技能课堂
ThinkPHP6.x 微实战--十天技能课堂

共26课时 | 1.6万人学习

ThinkPHP6.x API接口--十天技能课堂
ThinkPHP6.x API接口--十天技能课堂

共14课时 | 1.1万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号