跨Linux与Windows的Python Socket文件传输UnicodeDecodeError问题
跨系统文件传输编码错误修复方案
问题场景
将图片从树莓派(Linux客户端)传输至Windows笔记本(服务器)时,服务器端抛出编码错误:
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xff in position 5: invalid start byte
同一Windows机器上运行两端脚本时,文件可正常传输。
错误原因
这是TCP粘包导致的:TCP是流式传输协议,客户端连续调用send()发送文件名、文件大小、二进制文件数据时,操作系统可能会将多个send()的内容合并为一个数据包发送。
- 本地运行时,数据包拆分逻辑稳定,服务器能通过两次
recv()分别获取完整的文件名和文件大小; - 跨网络传输时,网络延迟或系统缓冲区差异,导致服务器第二次
recv()收到的是文件大小的部分数据+图片二进制开头数据(JPG文件开头包含0xff这类非UTF-8字节),解码时自然报错。
修正代码
客户端(client.py)
给文件名、文件大小添加明确的分隔符b"<SEP>",确保服务器能准确拆分数据:
import os import socket HOST = '192.168.2.80' # 服务器IP PORT = 3322 client = socket.socket(socket.AF_INET, socket.SOCK_STREAM) try: client.connect((HOST, PORT)) print(f"STATUS_MSG: Connected-Successfully-To-Server-IP-{HOST}") except: print("STATUS_MSG: Unable-To-Connect-To-Server") exit(0) # 获取文件信息并添加分隔符 file_name = "image1.jpg" file_size = os.path.getsize(file_name) # 将文件名、文件大小用分隔符拼接后发送 client.send(f"{file_name}<SEP>{file_size}".encode()) # 发送文件数据 with open(file_name, "rb") as file: data = file.read() client.sendall(data) client.send(b"<END>") client.close()
服务器端(server.py)
接收数据后按分隔符拆分,提取文件名和文件大小,再接收文件数据:
import os import socket HOST = '192.168.2.80' # 笔记本私有IP PORT = 3322 server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) server.bind((HOST, PORT)) print("STATUS_MSG: This-Is-Laptop") print("STATUS_MSG: Awaiting-Connection-From-Client") server.listen() try: communication_socket, addrs_of_client = server.accept() print(f"STATUS_MSG: Connection-Established-To-Client-IP-{addrs_of_client}") except: print("STATUS_MSG: Unable-To-Accept-Connection") exit(0) # 接收并拆分文件名和文件大小 info_data = communication_socket.recv(1024).decode() file_name, file_size = info_data.split("<SEP>") file_size = int(file_size) print(f"incoming file name = {file_name}") print(f"incoming file size = {file_size}") # 接收文件数据,按实际文件大小接收(比用<END>更可靠) file_path = os.path.join("./recvt", file_name) with open(file_path, "wb") as file: received_bytes = 0 while received_bytes < file_size: data = communication_socket.recv(min(1024, file_size - received_bytes)) if not data: break file.write(data) received_bytes += len(data) print("File Received Successfully") communication_socket.close() server.close()
扩展多文件循环双向传输思路
- 定义通信协议:给每个传输的数据包添加类型标识(比如
"FILE_NAME"、"FILE_DATA"、"END_TRANSFER"、"REQUEST_SEND"等),明确双方的交互逻辑; - 循环交互:在两端添加循环逻辑,允许用户选择发送/接收文件,或者自动轮询待传输文件;
- 双向通信:建立连接后保留socket连接,通过协议指令切换发送/接收角色,或建立两个独立socket分别处理发送和接收;
- 异常处理:添加断连重连、文件哈希校验、超时机制,提升跨系统传输稳定性。
内容的提问来源于stack exchange,提问作者Ali Furqan
相关产品推荐
相关产品推荐

