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

Python Socket客户端/服务端架构图片传输异常排查与解决方案

问题根源分析
  • 客户端接收逻辑错误:初始尝试recv(1024).decode('utf8')会读取服务端发送的前4字节长度数据,导致后续读取图片长度时拿到不完整或错误的字节,进而无法正确获取完整图片数据。
  • Socket流式传输特性:recv(n)无法保证一次性返回n字节数据,即使指定了图片总长度,也可能仅返回部分数据,必须循环接收直至凑齐所有字节。
修正后的服务端代码
import socket

host = 'localhost'
port = 50000

mySocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
mySocket.bind((host, port))
mySocket.listen()

while True:
    connexion, adresse = mySocket.accept()
    print(f"连接来自: {adresse}")
    
    # 读取本地图片二进制数据
    with open('WhatsApp Image 2023-10-16 at 17.49.56.jpeg', 'rb') as fichier_image:
        image_data = fichier_image.read()
    
    try:
        # 发送图片长度(固定4字节,大端序)
        image_size = len(image_data)
        print(f"图片总字节数: {image_size}")
        connexion.sendall(image_size.to_bytes(4, byteorder='big'))
        # 发送完整图片数据
        connexion.sendall(image_data)
        print("图片发送完成")
    except Exception as e:
        print(f"发送错误: {e}")
    finally:
        connexion.close()
    
    ch = input("<R>重新开始 <T>结束 ? ")
    if ch.upper() == "T":
        break

mySocket.close()
修正后的客户端代码
import socket
from io import BytesIO
from PIL import Image

host = 'localhost'
port = 50000

def recv_all(sock, target_length):
    """循环接收指定长度的数据,确保获取完整内容"""
    received_data = b''
    while len(received_data) < target_length:
        # 每次接收剩余长度的数据,避免浪费缓冲区
        chunk = sock.recv(target_length - len(received_data))
        if not chunk:
            raise ConnectionError("连接意外中断")
        received_data += chunk
    return received_data

myClient = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
myClient.connect((host, port))

try:
    # 先接收4字节的图片长度
    size_bytes = recv_all(myClient, 4)
    image_size = int.from_bytes(size_bytes, byteorder='big')
    print(f"预期接收图片长度: {image_size}")
    
    # 接收完整的图片二进制数据
    image_data = recv_all(myClient, image_size)
    print(f"实际接收字节数: {len(image_data)}")
    
    # 解析并显示图片
    image = Image.open(BytesIO(image_data))
    image.show()
except Exception as e:
    print(f"接收错误: {e}")
finally:
    myClient.close()
关键注意事项
  • 优先使用sendall():该方法会确保所有数据被发送完毕,而send()可能仅发送部分数据就返回。
  • 实现recv_all()工具函数:处理Socket流式传输的特性,避免因单次接收不完整导致数据损坏。
  • 统一传输协议:服务端和客户端必须约定固定的传输格式(如先4字节长度、再二进制数据),避免文本与二进制数据混淆。

内容的提问来源于stack exchange,提问作者Borris Kouadja NIANGORAN

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 14:15:26