如何使用Python实现多文件传输 解决仅能传输单文件的问题
问题根因
- 接收端仅支持单次文件接收:接收端和发送端建立连接后,只会执行一次文件接收逻辑,处理完第一个文件后就进入等待用户输入退出的状态,完全不会处理后续发送的第二个文件数据,这是第二次传输看不到文件的核心原因。
- TCP粘包风险:当前发送逻辑是连续发送文件名、文件大小的字节流,没有明确的边界分隔,一旦数据量累计触发TCP粘包,接收端会把文件名和文件大小的数据读混,直接导致文件解析失败。
修复代码
发送端修改后代码
import os import shutil import socket import struct sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.bind((socket.gethostname(), 22222)) sock.listen(5) print("Host Name: ", sock.getsockname()) client, addr = sock.accept() print(f"已连接客户端:{addr}") print("当你想要停止上传文件时输入 -> STOP <-") while True: original = input("Filepath:") if original == "STOP": # 发送停止标识告知接收端结束传输 client.send(struct.pack('i', 0)) break if not os.path.exists(original): print("文件路径不存在,请重新输入") continue filename = os.path.basename(original) target = r'C:\Users\Gasper\Desktop\transfer\filename' path = target.replace('filename', filename) shutil.copy(original, path) file_size = os.path.getsize(path) # 用struct打包固定长度头部,解决粘包:先传文件名长度,再传文件名,再传文件大小 filename_bytes = filename.encode() client.send(struct.pack('i', len(filename_bytes))) client.send(filename_bytes) client.send(struct.pack('q', file_size)) # 发送文件内容 with open(path, "rb") as file: while True: data = file.read(1024) if not data: break client.sendall(data) os.remove(path) print(f"{filename} 传输完成") print("所有文件传输完成!") input("按回车键退出...") sock.close()
接收端修改后代码
import socket import os import struct host = input("Host Name: ") sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) try: sock.connect((host, 22222)) print("连接成功") except: print("无法连接到服务端") exit(0) # 提前创建接收目录避免报错 if not os.path.exists("./rec"): os.makedirs("./rec") while True: # 先接收文件名长度,为0代表传输结束 filename_len = struct.unpack('i', sock.recv(4))[0] if filename_len == 0: break # 接收文件名 file_name = sock.recv(filename_len).decode() # 接收文件大小 file_size = struct.unpack('q', sock.recv(8))[0] recv_size = 0 with open(os.path.join("./rec", file_name), "wb") as file: while recv_size < file_size: # 每次最多读剩余需要接收的大小,避免多读下一个文件的头部 chunk = sock.recv(min(1024, file_size - recv_size)) if not chunk: break file.write(chunk) recv_size += len(chunk) print(f"{file_name} 接收完成,大小:{recv_size}字节") print("所有文件传输完成!") input("按回车键退出...") sock.close()
验证说明
修改后发送端可以连续输入多个文件路径传输,全部传完输入STOP即可结束,接收端会自动接收所有传输的文件存到rec目录下。
内容的提问来源于stack exchange,提问作者Gasper Melansek
相关产品推荐
相关产品推荐

