Python3 Socket文件传输异常:接收文件损坏但数据比对无差异
Python Socket 文件传输损坏问题的解决方案
我之前也踩过一模一样的坑!流程看起来正常但文件始终损坏,大概率是二进制文件处理模式错误或者Socket数据边界没处理好——毕竟Python3里字节串和字符串的区别很容易忽略,而且Socket是流式传输,不像本地文件那样有明确的结束标记。
常见问题根源
- 文件读写模式错误:用了文本模式(
r/w)而非二进制模式(rb/wb),这会让Python自动转换换行符(比如Windows的\r\n转成\n),直接破坏二进制文件的结构。 - 未明确文件大小:Socket流式传输下,接收端不知道什么时候该停止接收,可能提前截断数据,或者多收了无关数据。
- 发送/接收不完整:单次
send()或recv()不一定能处理所有数据,需要循环操作直到全部数据传输完成。
修正后的代码示例
server.py
import socket import os def send_file(): # 创建Socket对象 server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) server_socket.bind(('localhost', 9999)) server_socket.listen(1) print("等待客户端连接...") conn, addr = server_socket.accept() print(f"已连接:{addr}") # 要发送的文件路径 file_path = "test.bin" try: # 以二进制模式打开文件 with open(file_path, 'rb') as f: # 获取文件大小并发送(转成固定8字节的二进制格式) file_size = os.path.getsize(file_path) conn.sendall(file_size.to_bytes(8, byteorder='big')) # 循环发送文件内容,确保全部发送完成 while True: data = f.read(1024) if not data: break conn.sendall(data) print("文件发送完成") except Exception as e: print(f"发送出错:{e}") finally: conn.close() server_socket.close() if __name__ == "__main__": send_file()
client.py
import socket def receive_file(): client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) client_socket.connect(('localhost', 9999)) # 先接收文件大小,确定需要接收的总字节数 file_size_data = client_socket.recv(8) file_size = int.from_bytes(file_size_data, byteorder='big') print(f"预计接收文件大小:{file_size}字节") # 以二进制模式写入文件,避免编码转换 received_size = 0 with open("received_test.bin", 'wb') as f: while received_size < file_size: # 每次接收不超过1024字节,同时避免超出剩余需要接收的字节数 data = client_socket.recv(min(1024, file_size - received_size)) if not data: break f.write(data) received_size += len(data) # 取消下面的注释可以查看二进制数据进行比对 # print(data) print(f"文件接收完成,实际接收:{received_size}字节") client_socket.close() if __name__ == "__main__": receive_file()
关键修复点说明
- 二进制模式读写:所有文件操作都用
rb/wb,确保字节数据原封不动地读写,不会被编码或换行符转换破坏。 - 传输文件大小:先发送文件的总字节数,让接收端明确知道需要接收多少数据,彻底解决流式传输的边界问题。
- 循环发送/接收:用
sendall()确保数据全部发送,接收端循环直到收满文件大小的字节数,处理单次recv()无法获取全部数据的情况。
如果之前你是因为文本模式导致的问题,换成二进制模式后应该就能解决;如果是数据边界问题,加上文件大小的传输和循环接收逻辑就可以了。你可以取消代码里的print(data)注释,对比发送和接收的字节串,就能看到之前的差异点啦。
内容的提问来源于stack exchange,提问作者Fathy
相关产品推荐
相关产品推荐

