本地UDP接收数据出现丢包,求替代循环接收的可行方案
UDP接收数据丢失的排查与解决
你遇到的UDP接收数据丢失问题,导致本该是完整正弦波的接收数据呈现断裂波形。你怀疑是while循环接收速度不足,但实际原因通常和UDP的特性、系统缓冲区或处理逻辑有关,以下是具体的解决思路和改进方案:
一、核心原因分析
- UDP是无连接、不可靠协议:系统UDP接收缓冲区满时,新数据包会直接被丢弃,这是最常见的丢包原因
- 接收循环被阻塞:如果
struct.unpack或后续数据处理耗时,会耽误下一次recvfrom调用,导致缓冲区溢出 - 发送端速率过高:发送端发送数据的速度超过了接收端的处理和缓冲能力
二、针对性改进方案
1. 增大UDP接收缓冲区
系统默认的UDP接收缓冲区较小,调大它可以减少缓冲区溢出导致的丢包:
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # 将接收缓冲区设置为64KB(可根据实际情况调整,最大值受系统内核参数限制) sock.setsockopt(socket.SOL_SOCKET, socket.SO_RCVBUF, 65536) sock.bind((UDP_IP, UDP_PORT))
2. 用多线程分离接收与处理逻辑
如果数据处理(比如解包、存入队列)耗时,会阻塞接收循环。把接收逻辑放到单独线程,让接收和处理并行:
import socket import struct import threading import numpy as np UDP_IP = "127.0.0.1" UDP_PORT = 2000 data_fifo = [] # 线程锁保证队列操作的安全性 fifo_lock = threading.Lock() def receive_data(): sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) sock.setsockopt(socket.SOL_SOCKET, socket.SO_RCVBUF, 65536) sock.bind((UDP_IP, UDP_PORT)) while True: data, addr = sock.recvfrom(1472) temp = struct.unpack('368f', data) with fifo_lock: data_fifo.extend(temp) # 启动后台接收线程 recv_thread = threading.Thread(target=receive_data, daemon=True) recv_thread.start() # 主线程负责数据处理/绘图 while True: with fifo_lock: if data_fifo: # 示例:取出一批数据处理 process_chunk = data_fifo[:500] del data_fifo[:500] # 这里替换成你的数据处理或绘图逻辑 print(f"处理了{len(process_chunk)}个数据点") # 主线程可根据需求添加适当延时 # time.sleep(0.001)
3. 排查发送端与数据包完整性
- 确认发送端每次发送的数据包大小确实是1472字节(
368f对应368*4=1472字节,格式是匹配的) - 在发送端统计发送的数据包总数,接收端统计接收的数据包数,对比确认丢包发生在哪个环节
4. 非阻塞IO优化(可选)
如果不想用多线程,可以将socket设为非阻塞,配合select监听数据,避免阻塞等待:
import select sock.setblocking(False) while True: # 等待数据到达,超时0.1秒,期间可处理其他逻辑 ready, _, _ = select.select([sock], [], [], 0.1) if ready: data, addr = sock.recvfrom(1472) temp = struct.unpack('368f', data) with fifo_lock: data_fifo.extend(temp) # 插入数据处理逻辑
三、验证步骤
- 先去掉所有数据处理逻辑,只统计接收的数据包数量,看是否还丢包,排查是否是处理逻辑导致的阻塞
- 查看系统UDP缓冲区的实际大小(可通过
sysctl net.core.rmem_max等命令),确保设置的缓冲区值在系统允许范围内
内容的提问来源于stack exchange,提问作者Eind997
相关产品推荐
相关产品推荐

