You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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()

关键修复点说明

  1. 二进制模式读写:所有文件操作都用rb/wb,确保字节数据原封不动地读写,不会被编码或换行符转换破坏。
  2. 传输文件大小:先发送文件的总字节数,让接收端明确知道需要接收多少数据,彻底解决流式传输的边界问题。
  3. 循环发送/接收:用sendall()确保数据全部发送,接收端循环直到收满文件大小的字节数,处理单次recv()无法获取全部数据的情况。

如果之前你是因为文本模式导致的问题,换成二进制模式后应该就能解决;如果是数据边界问题,加上文件大小的传输和循环接收逻辑就可以了。你可以取消代码里的print(data)注释,对比发送和接收的字节串,就能看到之前的差异点啦。

内容的提问来源于stack exchange,提问作者Fathy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.19 08:29:24