Python Socket实现客户端向服务器上传文件时传输卡住问题求助
问题原因
- TCP为面向字节流的传输协议,没有内置消息边界标识。当前服务端逻辑以
recv()返回空值作为接收结束的判断条件,而recv()仅会在对端连接断开时才会返回空值。客户端完成所有数据发送后未主动断开连接、也未发送传输结束标记,因此服务端会持续阻塞在recv()调用等待新数据,直到客户端进程终止触发连接断开。 - 代码存在隐性逻辑问题:客户端先发送文件名编码字节,再发送文件内容,服务端未做边界拆分,会将文件名字节直接写入目标文件,最终得到的文件内容存在冗余错误。
解决方案
根据场景可选择以下两种方案:
方案1:定义传输协议边界(推荐,支持长连接复用)
提前约定传输结构,先发送固定长度的元数据头(包含文件名长度、文件总大小),服务端读取头信息后按指定长度接收文件内容,收满即停止,无需等待连接断开。
修改后代码示例:
客户端代码
import struct def UpdateFileOnServer(file): print("[!] Uploading file to server: ", file) file_path = clientFolder + file with open(file_path, "rb") as f: file_content = f.read() file_size = len(file_content) file_name_bytes = file.encode() file_name_len = len(file_name_bytes) # 打包头信息:2字节存储文件名长度,4字节存储文件总大小 header = struct.pack("<HI", file_name_len, file_size) s.sendall(header) s.sendall(file_name_bytes) s.sendall(file_content) # 可等待服务端返回上传成功响应 resp = s.recv(10) if resp == b"upload_ok": print("[!] File upload confirmed by server.")
服务端代码
import struct # 读取固定6字节的头信息 header = conn.recv(6) file_name_len, file_size = struct.unpack("<HI", header) # 读取指定长度的文件名 file_name = conn.recv(file_name_len).decode() fileLocation = 你的自定义存储路径拼接逻辑 + file_name received_size = 0 with open(fileLocation, "wb") as f: print("[!] File received! Downloading...") while received_size < file_size: read_len = min(4096, file_size - received_size) data = conn.recv(read_len) if not data: # 连接异常中断处理 break f.write(data) received_size += len(data) # 回传上传成功响应 conn.send(b"upload_ok")
方案2:半关闭连接(仅适合单次传输后无需复用连接的场景)
无需修改传输逻辑,客户端发送完所有数据后调用s.shutdown(1)关闭写方向流,此时服务端的recv()会返回空值,即可正常结束接收流程。注意该方法会导致连接无法再复用,仅适合单连接单次上传的场景。
修改后客户端发送完成后增加代码:
s.sendall(file) # 新增半关闭逻辑 s.shutdown(1) print("[!] File has been sent.")
内容的提问来源于stack exchange,提问作者user16618827
相关产品推荐
相关产品推荐

