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

Python Socket文件发送异常:文件提前结束问题求助

问题分析与修复方案

我来帮你排查这个文件传输提前终止的问题,你的代码里有几个关键逻辑错误,直接导致了文件发送不完整:

一、服务器端核心问题:文件发送循环逻辑错误

你的send_file函数用read变量累加固定的MAX_LENGTH_OF_SEND来判断发送进度,这个逻辑有两个致命缺陷:

  1. 最后一块数据丢失:当文件剩余字节不足MAX_LENGTH_OF_SEND时,你已经读取到了这块数据,但read += MAX_LENGTH_OF_SEND后会超过文件总大小,循环直接终止,导致这块数据永远不会被发送。
  2. 小文件完全无法发送:如果文件大小≤MAX_LENGTH_OF_SEND,初始read累加后就等于或超过了文件大小,循环根本不会执行,第一块数据直接被丢弃。

修复后的服务器send_file函数

我们应该抛弃read变量,直接循环读取文件直到返回空字节(表示文件结束),每次读取后立即发送:

MAX_LENGTH_OF_SEND = 9999
def send_file(path, client_socket):
    """send a file to the client. if succeeded return success, else return error massage
    :param path: path of the file to send
    :param client_socket: the socket of the client to send to
    :return: if success return 'success sending a file' else, return error massage
    """
    try:
        size = os.stat(path).st_size
        print(f"File size to send: {size}")
        # Send the length of the file to the client
        send(str(size), client_socket)
        
        with open(path, "rb") as file1:
            while True:
                chunk = file1.read(MAX_LENGTH_OF_SEND)
                if not chunk:
                    # No more data, exit loop
                    break
                binary_send(chunk, client_socket)
                print(f"Sent chunk of size: {len(chunk)}")
        
        print(f"The file {path} has been sent completely")
    except Exception as e:
        print(f"Couldn't send file because {e}")
        return "Error: " + str(e)
    return "success sending a file"

二、长度传输的一致性问题

你的send和binary_send函数直接发送字符串形式的长度,客户端接收时固定读取2或4字节,这会导致长度字符串超过位数时被截断(比如文件大小是180000,字符串长度是6,客户端receive_msg里recv(2)只能拿到前两位)。

修复长度传输逻辑

统一用4位固定长度的字符串发送长度,确保客户端能正确接收:

服务器端修改send和binary_send:

def send(msg, client_socket):
    """ sending a message to a client by sending the length of the message first
    :param msg: the message to send
    :param client_socket: the client to send the message
    """
    msg_length = len(msg)
    # Send length as 4-digit padded string (e.g., 6 becomes "0006")
    client_socket.send(f"{msg_length:04d}".encode())
    client_socket.send(msg.encode())

def binary_send(msg, client_socket):
    """ sending a binary message to a client by sending the length first
    :param msg: the binary message to send
    :param client_socket: the client to send the message
    """
    chunk_length = len(msg)
    client_socket.send(f"{chunk_length:04d}".encode())
    client_socket.send(msg)
    print(f"Sent binary chunk of size: {chunk_length}")

客户端修改receive_msg:

def receive_msg(my_socket):
    """receive a message from the server
    :param my_socket: the socket to get from
    :return: the message
    """
    # Receive 4-digit length string, strip any whitespace
    length_str = my_socket.recv(4).decode().strip()
    length = int(length_str)
    return my_socket.recv(length).decode()

三、客户端的接收计数错误

你的客户端代码里把given += length误写成了size += length,这会导致given < size的循环条件永远成立——size不断变大,given永远追不上,客户端会一直等待接收,直到服务器断开连接,看起来就像服务器提前终止了发送。

修复客户端接收循环:

data = receive_msg(my_socket)
if data.startswith("Error:"):
    print(data)
else:
    if SENT_PICTURE_PATH.endswith("\\"):
        path = SENT_PICTURE_PATH + request[1]
    else:
        path = SENT_PICTURE_PATH + "\\" + request[1]
    if not os.path.exists(os.path.dirname(path)):
        os.makedirs(os.path.dirname(path))
    with open(path, "wb") as file:
        size = int(data)
        given = 0
        error = False
        while not error and given < size:
            # Receive 4-digit chunk length
            length_str = my_socket.recv(4).decode().strip()
            length = int(length_str)
            print(f"Receiving chunk of size: {length}")
            data = my_socket.recv(length)
            print(f"Received data: {data[:20]}...")  # Print first 20 bytes for debug
            try:
                if data.decode().startswith("Error:"):
                    error = True
                    print(data.decode())
            except (UnicodeDecodeError, ValueError):
                pass
            if not error:
                file.write(data)
                given += length  # Fix: update given, not size
        print(f"File received, total bytes: {given}")

总结

修复后,服务器会完整发送每一块文件数据,客户端能正确计数已接收字节,长度传输也不会再出现截断问题,应该就能解决文件提前终止发送的问题了。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.09 21:03:01