使用Crypto库加密文件时接收端解码文件大小遇UnicodeDecodeError求助
文件加密传输中接收端解码文件大小失败的解决方法
问题根源
TCP是流式传输协议,发送端连续调用send的内容会被操作系统合并为一个或多个TCP报文发送,接收端的recv(1024)会读取当前缓冲区所有可用数据,并非严格对应单个send的内容。你的代码中,第一次recv可能已经把文件名、部分文件大小甚至加密数据一并读走,导致第二次recv拿到的是加密后的二进制数据,无法用UTF-8解码,触发UnicodeDecodeError。
解决方案
需要通过明确的边界标识或固定长度传输来区分不同数据段,确保接收端能准确读取每个字段。
方案1:使用分隔符区分数据段
在每个数据字段末尾添加唯一分隔符(比如\n),接收端按分隔符读取完整字段。
发送端修改代码
# 发送文件名,末尾加换行符作为分隔 client.send(b'file.txt\n') # 发送文件大小,末尾加换行符 client.send(f"{file_size}\n".encode()) # 发送加密数据 client.sendall(encrypted) # 发送结束标记 client.send(b'<END>') client.close()
接收端修改代码
先实现一个按分隔符读取完整数据的辅助函数:
def recv_until(conn, delimiter): buffer = b'' while True: chunk = conn.recv(1024) if not chunk: return None buffer += chunk if delimiter in buffer: data, _ = buffer.split(delimiter, 1) return data # 读取文件名 file_name = recv_until(client, b'\n').decode() print(file_name) # 读取文件大小并转换为整数 file_size = int(recv_until(client, b'\n').decode()) print(file_size) # 读取加密数据直到结束标记 encrypted_data = b'' while True: chunk = client.recv(1024) if b'<END>' in chunk: encrypted_data += chunk.split(b'<END>')[0] break encrypted_data += chunk
方案2:固定长度传输(更可靠)
用struct模块将数据长度打包为固定字节数(比如4字节无符号整数),先发送长度,再发送对应长度的数据。
发送端修改代码
import struct # 发送文件名:先传长度,再传内容 name_bytes = b'file.txt' client.send(struct.pack('!I', len(name_bytes))) # 打包为大端字节序的4字节整数 client.send(name_bytes) # 发送文件大小:打包为4字节整数 client.send(struct.pack('!I', file_size)) # 发送加密数据和结束标记 client.sendall(encrypted) client.send(b'<END>') client.close()
接收端修改代码
import struct # 读取文件名长度(4字节) name_len_data = client.recv(4) name_len = struct.unpack('!I', name_len_data)[0] # 读取对应长度的文件名 file_name = client.recv(name_len).decode() print(file_name) # 读取文件大小(4字节) file_size_data = client.recv(4) file_size = struct.unpack('!I', file_size_data)[0] print(file_size) # 读取加密数据直到结束标记 encrypted_data = b'' while True: chunk = client.recv(1024) if b'<END>' in chunk: encrypted_data += chunk.split(b'<END>')[0] break encrypted_data += chunk
内容的提问来源于stack exchange,提问作者Dulitha Bandaranayake
相关产品推荐
相关产品推荐

