UDP传输pickle序列化数据 接收端反序列化报UnicodeDecodeError
UDP传输OpenCV帧pickle解码报错修复
报错原因
你碰到的UnicodeDecodeError: 'ascii' codec can't decode byte 0xff in position 0是Python3下pickle处理二进制数据的典型问题:
- Python3的
pickle.loads()默认用ASCII编码解析输入,而JPEG压缩后的帧头第一个字节就是0xff,超出ASCII可打印字符范围(0-127),直接调用必然抛错 - 你贴的代码缺了摄像头、socket的初始化逻辑,也没做UDP传输的坏帧容错,就算改了解码参数也容易运行崩溃
修复步骤
1. 修正pickle解码参数
给pickle.loads显式指定encoding='bytes',就能解决编码不兼容的问题,把报错行改成:
data = pickle.loads(data, encoding='bytes')
2. 补全两端代码逻辑,增加容错
UDP传输本身不保证可靠,遇到丢包、数据截断时pickle会解码失败,必须加异常捕获跳过坏帧,避免程序直接退出。以下是可直接运行的完整代码:
发送端代码
import cv2 import socket import pickle import numpy as np # 初始化本地摄像头 cap = cv2.VideoCapture(0) # 初始化UDP发送套接字 sk = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # 替换为接收端PC的实际局域网IP和监听端口 RECV_IP = "192.168.3.45" RECV_PORT = 9000 while True: ret, frame = cap.read() if not ret: break # 压缩为JPEG,质量设为30控制单帧体积,减少UDP丢包 ret, jpg_buffer = cv2.imencode(".jpg", frame, [int(cv2.IMWRITE_JPEG_QUALITY), 30]) send_data = pickle.dumps(jpg_buffer) sk.sendto(send_data, (RECV_IP, RECV_PORT)) # 按ESC键停止发送 if cv2.waitKey(1) == 27: break cap.release() cv2.destroyAllWindows() sk.close()
接收端代码
import cv2 import socket import pickle import numpy as np # 初始化UDP监听套接字 sk = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # 绑定本地所有网卡的对应端口,端口要和发送端配置一致 sk.bind(("0.0.0.0", 9000)) while True: recv_data, client_addr = sk.recvfrom(1000000) try: # 指定编码解决ASCII解码报错 jpg_buffer = pickle.loads(recv_data, encoding="bytes") # 解码JPEG为OpenCV可显示的帧格式 frame = cv2.imdecode(np.frombuffer(jpg_buffer, dtype=np.uint8), cv2.IMREAD_COLOR) if frame is not None: cv2.imshow("receive", frame) # 按回车键停止接收 if cv2.waitKey(10) == 13: break except Exception: # 丢包、坏帧直接跳过,不中断程序 continue cv2.destroyAllWindows() sk.close()
运行注意事项
- 两台PC必须在同一局域网下,提前关闭系统防火墙或者放开对应UDP端口的入站规则,否则会收不到数据
- 不要把JPEG压缩质量设太高,单帧体积控制在60KB以内能大幅降低UDP丢包概率,传输更流畅
内容的提问来源于stack exchange,提问作者Koushik
相关产品推荐
相关产品推荐

