Python Socket跨机器传输截图时多图合并为单个文件的问题
问题分析
跨机器传输时截图合并为单个大文件的核心原因是TCP粘包,加上原代码的分隔逻辑存在漏洞:
- TCP是流式协议,跨机器网络延迟会导致服务器发送的图片数据与分隔符
b"full"粘在一起,客户端无法正确识别每个图片的边界 - 客户端判断逻辑错误:当收到包含
b"full"的粘包数据时,会直接写入文件,且b"full"可能被遗留到下一次接收循环,导致后续图片数据被追加到同一文件
解决方案
采用固定长度的头部+数据体的传输协议,先发送图片数据的字节长度(用struct打包为固定4字节),再发送图片内容,从根本上避免粘包问题。同时优化服务端流程,无需将截图保存到本地磁盘,直接在内存中处理。
修改后的服务端代码
import time import pyautogui import struct from socket import * from io import BytesIO host = "192.168.43.79" port = 4446 s = socket(AF_INET, SOCK_STREAM) s.bind((host, port)) print("Listening for connections.. ") q, addr = s.accept() i = 0 while True: # 截图直接存入内存字节流,无需写入磁盘 screenshot = pyautogui.screenshot() img_byte_arr = BytesIO() screenshot.save(img_byte_arr, format='JPEG') img_byte_arr = img_byte_arr.getvalue() # 发送图片长度(打包为4字节大端整数) img_len = struct.pack('!I', len(img_byte_arr)) q.send(img_len) # 发送图片数据 q.sendall(img_byte_arr) i += 1 time.sleep(0.3)
修改后的客户端代码
import struct from socket import * host = "192.168.43.79" port = 4446 s = socket(AF_INET, SOCK_STREAM) s.connect((host, port)) i = 0 while True: # 先接收4字节的图片长度 len_data = s.recv(4) if not len_data: break # 连接断开 img_len = struct.unpack('!I', len_data)[0] # 接收指定长度的图片数据 received_len = 0 with open(f"{i}s.jpg", "wb") as f: while received_len < img_len: chunk = s.recv(min(4096, img_len - received_len)) if not chunk: break f.write(chunk) received_len += len(chunk) i += 1
关键优化点
- 避免磁盘IO:服务端用
BytesIO将截图直接转为内存字节流,无需保存本地文件,提升传输效率 - 明确数据边界:通过
struct打包固定长度的头部,客户端可精准计算需要接收的图片数据量,彻底解决粘包问题 - 健壮的接收逻辑:客户端按剩余需要接收的长度调整每次recv的大小,确保数据完整接收
内容的提问来源于stack exchange,提问作者Shadowhunter 1
相关产品推荐
相关产品推荐

