Python Socket文件发送异常:文件提前结束问题求助
问题分析与修复方案
我来帮你排查这个文件传输提前终止的问题,你的代码里有几个关键逻辑错误,直接导致了文件发送不完整:
一、服务器端核心问题:文件发送循环逻辑错误
你的send_file函数用read变量累加固定的MAX_LENGTH_OF_SEND来判断发送进度,这个逻辑有两个致命缺陷:
- 最后一块数据丢失:当文件剩余字节不足
MAX_LENGTH_OF_SEND时,你已经读取到了这块数据,但read += MAX_LENGTH_OF_SEND后会超过文件总大小,循环直接终止,导致这块数据永远不会被发送。 - 小文件完全无法发送:如果文件大小≤
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
相关产品推荐
相关产品推荐

