Python TCP Socket多文件传输时所有数据存入首个文件问题求解
问题根因
- 核心问题:TCP是流式传输协议,本身没有数据边界,你已经提前传输了每个文件的大小元数据,但接收端的读取逻辑没有使用这个元数据做截断。现有接收代码的
while True会持续从socket缓冲区读取所有能拿到的数据,直到连接断开才停止,所以第一个文件的写入逻辑直接把所有后续文件的内容全部写入了第一个文件,后续循环创建新文件时socket缓冲区已经没有数据,自然生成的都是0B空文件。 - 次要问题:代码存在冗余和语法疏漏,发送端用
with open管理文件句柄会自动关闭文件,末尾多余的f.close()没有必要;接收端末尾的conn.close漏写括号,不会实际执行连接关闭操作。
修复方案
接收端核心修改逻辑为:每个文件启动接收前统计已接收字节数,当已接收字节数等于当前文件的预设大小时,立即退出当前文件的写入循环,开始处理下一个文件。同时为了避免最后一次读取误拿后续文件的内容,每次调用recv时取缓冲区大小和当前文件剩余未接收大小的较小值作为读取上限。
优化后发送端代码
BUFFER_SIZE = 4096 def send_data(conn, file_name, file_size, numbers_files): for i in range(numbers_files): bar = tqdm.tqdm(range(file_size[i]), f"Sending {file_name[i]}, to {ADDR}", unit="B", unit_scale=True, unit_divisor=BUFFER_SIZE) # with语句会自动管理文件句柄,无需手动close with open(file_name[i], "rb") as f: while True: data = f.read(BUFFER_SIZE) if not data: break conn.sendall(data) msg = conn.recv(BUFFER_SIZE).decode() bar.update(len(data))
优化后接收端代码
BUFFER_SIZE = 4096 def receive_data(conn, file_info): file_name = file_info[0] file_size = file_info[1] numbers_files = file_info[2] for i in range(numbers_files): received_size = 0 # 新增:统计当前文件已接收字节数 bar = tqdm.tqdm(range(file_size[i]), f"Receiving {file_name[i]}", unit="B", unit_scale=True, unit_divisor=BUFFER_SIZE) with open(file_name[i], "wb") as f: # 循环结束条件修改为:已接收大小等于当前文件总大小 while received_size < file_size[i]: # 取最小值避免多读后续文件的内容 data = conn.recv(min(BUFFER_SIZE, file_size[i] - received_size)) if not data: break f.write(data) received_size += len(data) conn.send("Data received".encode()) bar.update(len(data)) conn.close() # 补全括号,实际执行关闭操作
内容的提问来源于stack exchange,提问作者Toni404
相关产品推荐
相关产品推荐

