Python屏幕共享Socket项目跨设备运行pickle数据截断报错求解
错误根源
你当前的错误是TCP流接收逻辑判断错误导致的:
- 你用
if len(dataBin_) < BUFFER: break作为接收完一帧数据的判断条件,这个逻辑仅在本地环回传输时成立,本地传输数据不会被拆分成多个小于BUFFER的包。 - 跨网络传输时,TCP会根据网络情况拆包,很可能出现某次recv返回的数据长度小于BUFFER但实际整帧数据还没传完的情况,你提前终止了接收,拿到的pickle数据不完整,就会触发
_pickle.UnpicklingError: pickle data was truncated错误。
解决方案
在发送数据前先发送固定长度的头部,告知接收端当前帧的总长度,接收端按指定长度接收完整数据后再做反序列化即可解决问题。
修改后Client.py代码
import socket, pickle, time, cv2, struct import pyautogui import numpy as np # Constants BUFFER = 1024 * 8 ADDR = '192.168.20.4' PORT = 9090 # Connect to Server client = socket.socket(socket.AF_INET, socket.SOCK_STREAM) client.connect((ADDR, PORT)) # Cool down time time.sleep(2) # Stream Screen while True: screen = np.array(pyautogui.screenshot()) screenGray = cv2.cvtColor(screen, cv2.COLOR_BGR2GRAY) lowResGrayImg = cv2.resize(screenGray, (1280,800), fx=0, fy=0, interpolation=cv2.INTER_CUBIC) if client.recv(1) == b's': # 序列化数据 data = pickle.dumps(lowResGrayImg) # 打包数据长度为4字节固定头部 head = struct.pack('I', len(data)) # 先发送头部再发送数据,sendall确保数据全部发出 client.sendall(head) client.sendall(data)
修改后Server.py代码
import socket, pickle, cv2, struct # CONSTANTS BUFFER = 1024 * 8 ADDR = '192.168.20.4' PORT = 9090 # Create Server server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) server.bind((ADDR, PORT)) server.listen(1) def recv_exact(client, length): # 精确接收指定长度的字节数据,避免提前终止 data = b'' while len(data) < length: chunk = client.recv(min(BUFFER, length - len(data))) if not chunk: raise ConnectionError("客户端断开连接") data += chunk return data # Display Image def display(client): while True: # Get Data client.send(b's') # 先接收4字节头部,获取数据总长度 head = recv_exact(client, 4) data_len = struct.unpack('I', head)[0] # 按长度接收完整的pickle数据 dataBin = recv_exact(client, data_len) # Display Screen screen = pickle.loads(dataBin) cv2.imshow('Screen', screen) cv2.waitKey(1) # Accept Connections client, address = server.accept() print(f'{address[0]} is connected!') print(client.recv(10)) display(client)
额外排查项
如果修改后仍有问题可检查以下内容:
- 服务端和客户端Python大版本保持一致,不同大版本的pickle序列化格式不兼容
- 两端防火墙没有拦截9090端口的数据包
- 网络延迟过高时可适当调大BUFFER值减少接收循环次数
内容的提问来源于stack exchange,提问作者Falah
相关产品推荐
相关产品推荐

