You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

通过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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 16:40:56