UDP checksum错误时触发重传请求而非丢包的Python socket实现问询
UDP丢包重传实现方案
首先直接给出结论:Python 标准库的socket模块没有内置的标志位或回调逻辑,可以在UDP包被丢弃时主动触发用户态操作。
本质原因是UDP本身是无连接的不可靠协议,操作系统内核收到校验和错误的UDP包后会直接静默丢弃,既不会向应用层上报丢包通知,也不会给发送端返回报错信息,所以应用层无法通过系统自带的机制感知到这类丢包事件。
你要实现的丢包重传逻辑完全可以在应用层自行实现,方案如下:
- 给每个UDP包加连续递增的序号字段
你可以在单片机发送的UDP包头预留2字节空间存储连续递增的包序号,后面再放业务数据。Python服务端收到包后先解析序号,维护一个「最近连续收到的最大序号」变量:如果新收到的序号比预期的序号大,中间缺失的序号对应的就是已经丢失的包,此时你可以主动向单片机发送重传请求,请求报文中携带需要重传的序号列表即可。 - 叠加应用层校验覆盖校验错误场景
除了UDP自带的校验和,你可以在包头额外增加1字节的自定义校验位(比如CRC8),即使出现极个别漏过内核UDP校验的错误包,你可以在应用层识别后直接丢弃,这类包的序号也会形成序号缺口,同样会触发重传逻辑。 - 调整socket接收缓冲区减少非传输类丢包
你可以通过setsockopt调大UDP接收缓冲区,避免因服务端处理不及时导致内核缓冲区满产生的被动丢包,参考代码如下:import socket # 初始化UDP socket udp_server = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # 把接收缓冲区调大到1MB,可根据实际传输速率调整大小 udp_server.setsockopt(socket.SOL_SOCKET, socket.SO_RCVBUF, 1024 * 1024) udp_server.bind(("0.0.0.0", 你的服务端口)) - 单片机侧配合实现缓存逻辑
单片机侧需要缓存最近发送的N个数据包(缓存大小根据你允许的最大重传时延设置),收到服务端的重传请求后,直接返回对应序号的数据包即可。
内容的提问来源于stack exchange,提问作者Will Powell
相关产品推荐
相关产品推荐

