通过TCP传输Serde JSON时反序列化出现'Trailing Characters'错误
解决Rust Serde枚举TCP传输反序列化的"trailing characters"错误
在使用Serde序列化Rust枚举通过TCP传输时,服务器本地序列化反序列化正常,但客户端接收时触发Error("trailing characters") panic,错误列数总是比序列化JSON长度多1。
核心原因
TCP是无消息边界的字节流协议,直接发送序列化后的JSON字节时,客户端无法准确判断单条消息的结束位置。可能一次性读取了多条消息的部分内容,或者读取到了额外的字节,导致Serde反序列化时发现多余字符。
解决方法
1. 给消息添加长度前缀(推荐)
通过在每条消息前发送固定长度的字节表示消息长度,让接收端可以精确读取对应长度的字节,避免读取多余内容。
发送端(服务器)代码:
use serde_json; use std::io::Write; use std::net::TcpStream; use byteorder::{BigEndian, WriteBytesExt}; fn send_message(stream: &mut TcpStream, msg: &Message) -> Result<(), Box<dyn std::error::Error>> { // 序列化为JSON字节数组 let json_bytes = serde_json::to_vec(msg)?; // 发送长度前缀(u32类型,大端序保证跨平台兼容性) stream.write_u32::<BigEndian>(json_bytes.len() as u32)?; // 发送实际的JSON字节 stream.write_all(&json_bytes)?; // 确保数据全部发送出去 stream.flush()?; Ok(()) }
接收端(客户端)代码:
use serde_json; use std::io::Read; use std::net::TcpStream; use byteorder::{BigEndian, ReadBytesExt}; fn receive_message(stream: &mut TcpStream) -> Result<Message, Box<dyn std::error::Error>> { // 先读取4字节的长度前缀 let msg_len = stream.read_u32::<BigEndian>()? as usize; // 创建对应长度的缓冲区,精确读取消息字节 let mut json_bytes = vec![0; msg_len]; stream.read_exact(&mut json_bytes)?; // 反序列化字节为Message枚举 let msg = serde_json::from_slice(&json_bytes)?; Ok(msg) }
需要在Cargo.toml中添加依赖:
[dependencies] serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" byteorder = "1.5"
2. 使用分隔符分隔消息
在每条序列化后的消息末尾添加一个特殊分隔符(如\n),接收端读取字节直到遇到分隔符,截取分隔符前的内容进行反序列化。
注意:如果JSON内容本身包含分隔符(比如字符串里的\n),会导致错误分割,因此这种方法仅适用于消息内容不会包含分隔符的场景。
3. 切换为二进制序列化格式
使用bincode这类专为二进制流设计的序列化库,它默认支持长度前缀,无需手动处理消息边界,同时序列化后的体积更小,效率更高。
发送端代码:
use bincode; use std::io::Write; use std::net::TcpStream; fn send_message(stream: &mut TcpStream, msg: &Message) -> Result<(), Box<dyn std::error::Error>> { let bytes = bincode::serialize(msg)?; stream.write_all(&bytes)?; stream.flush()?; Ok(()) }
接收端代码:
use bincode; use std::io::Read; use std::net::TcpStream; fn receive_message(stream: &mut TcpStream) -> Result<Message, Box<dyn std::error::Error>> { // bincode默认自动处理长度前缀,直接从流中反序列化 let msg: Message = bincode::deserialize_from(stream)?; Ok(msg) }
添加bincode依赖到Cargo.toml:
[dependencies] serde = { version = "1.0", features = ["derive"] } bincode = "1.3"
内容的提问来源于stack exchange,提问作者dakota
相关产品推荐
相关产品推荐

