使用Socket实现文件收发时遭遇UnicodeDecodeError错误求助
解决Socket文件收发的UnicodeDecodeError问题
错误原因
出现UnicodeDecodeError: 'utf-8' codec can't decode byte 0xff in position 0: invalid start byte的核心问题是TCP粘包:发送端连续调用send()发送文件名、文件大小和二进制文件数据时,TCP协议会将这些小数据包合并发送。接收端第一次调用recv(1024)可能同时收到文件名、部分文件大小,甚至开头的二进制文件数据,此时对混合了二进制的字节流执行.decode()就会触发解码错误。
此外发送端代码还存在两个明显问题:
- 错误获取了无关文件
send_file.txt的大小,而非要发送的image.jpg; - 没有处理发送数据时的粘包问题,导致接收端无法准确拆分不同类型的数据。
修复方案
- 用分隔符区分数据段:在发送文件名、文件大小后添加特殊分隔符(如
b"<SEP>"),接收端按分隔符拆分数据; - 修正文件大小获取逻辑:改为获取目标文件的大小;
- 正确处理结束标记:接收端检测到结束标记后,截断掉标记部分再写入文件;
- 进度条按需更新:根据实际接收的字节数更新进度,避免进度虚高。
修改后的代码
发送端代码
import os import socket client = socket.socket(socket.AF_INET, socket.SOCK_STREAM) client.connect(("localhost", 9999)) file_path = "image.jpg" file_size = os.path.getsize(file_path) # 发送文件名+分隔符,文件大小+分隔符 client.send(f"{file_path}<SEP>{file_size}".encode()) with open(file_path, "rb") as file: # 分块发送文件数据,避免一次性读取大文件占用过多内存 while chunk := file.read(1024): client.sendall(chunk) # 发送结束标记 client.send(b"<DATA_END>") client.close()
接收端代码
import socket import tqdm server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) server.bind(("localhost", 9999)) server.listen() client, addr = server.accept() # 接收并拆分头部数据(文件名+文件大小) header = b"" while b"<SEP>" not in header: header += client.recv(1024) file_name, file_size = header.decode().split("<SEP>") file_size = int(file_size) with open(file_name, "wb") as file: file_bytes = b"" done = False progress = tqdm.tqdm(unit="B", unit_scale=True, unit_divisor=1000, total=file_size) while not done: data = client.recv(1024) # 检测结束标记 if b"<DATA_END>" in data: # 截断结束标记,只保留有效文件数据 file_bytes += data[:data.find(b"<DATA_END>")] done = True else: file_bytes += data # 更新实际接收的字节数 progress.update(len(data)) file.write(file_bytes) client.close() server.close()
内容的提问来源于stack exchange,提问作者CJ-Programmer
相关产品推荐
相关产品推荐

