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

Rust通用TCP/UDP服务端客户端:枚举与字节的序列化反序列化实现

Rust TCP/UDP通用消息系统:枚举序列化/反序列化实现方案

这个思路完全可行,是网络服务/游戏场景中常用的消息建模方式,以下是两种落地方案:

一、用成熟序列化库快速实现(推荐)

基于serde(Rust生态最通用的序列化框架)搭配二进制序列化库borsh(专为高性能二进制场景设计,对枚举支持友好)实现,无需手动处理变体ID和字节转换。

步骤1:添加依赖

在Cargo.toml中加入:

[dependencies]
serde = { version = "1.0", features = ["derive"] }
borsh = "1.0"

步骤2:给枚举添加序列化/反序列化派生宏

修改枚举定义:

use serde::{Serialize, Deserialize};

#[derive(Serialize, Deserialize, Debug, Clone)]
enum Messages {
    Welcome,
    Position(f32, f32),
    Damages(u8),
}

步骤3:实现泛型send和message_received函数

use borsh::{BorshSerialize, BorshDeserialize};

// 序列化消息并返回字节流+变体ID
fn send<E: BorshSerialize + Serialize>(message: E) -> Result<(Vec<u8>, usize), borsh::Error> {
    let data = message.try_to_vec()?;
    // 从序列化逻辑中提取变体ID(基于枚举定义顺序)
    let variant_id = get_variant_id(&message);
    Ok((data, variant_id))
}

// 从字节流反序列化消息
fn message_received<E: BorshDeserialize>(data: Vec<u8>) -> Result<E, borsh::Error> {
    E::try_from_slice(&data)
}

// 辅助函数:提取枚举变体ID
fn get_variant_id<E: Serialize>(message: &E) -> usize {
    use serde::ser::{Serializer, SerializeStructVariant};
    
    struct IdSerializer;
    impl Serializer for IdSerializer {
        type Ok = usize;
        type Error = serde::ser::Error;
        type SerializeSeq = serde::ser::Impossible<usize, Self::Error>;
        type SerializeTuple = serde::ser::Impossible<usize, Self::Error>;
        type SerializeTupleStruct = serde::ser::Impossible<usize, Self::Error>;
        type SerializeTupleVariant = serde::ser::Impossible<usize, Self::Error>;
        type SerializeMap = serde::ser::Impossible<usize, Self::Error>;
        type SerializeStruct = serde::ser::Impossible<usize, Self::Error>;
        type SerializeStructVariant = IdStructSerializer;

        fn serialize_struct_variant(
            self,
            _: &'static str,
            index: usize,
            _: &'static [&'static str],
            _: impl serde::ser::SerializeStructVariantVisitor,
        ) -> Result<Self::Ok, Self::Error> {
            Ok(index)
        }

        // 其他方法默认返回错误(仅处理结构体变体)
        fn serialize_bool(self, _: bool) -> Result<Self::Ok, Self::Error> {
            Err(serde::ser::Error::custom("not a struct variant"))
        }
        fn serialize_i8(self, _: i8) -> Result<Self::Ok, Self::Error> {
            Err(serde::ser::Error::custom("not a struct variant"))
        }
        fn serialize_i16(self, _: i16) -> Result<Self::Ok, Self::Error> {
            Err(serde::ser::Error::custom("not a struct variant"))
        }
        fn serialize_i32(self, _: i32) -> Result<Self::Ok, Self::Error> {
            Err(serde::ser::Error::custom("not a struct variant"))
        }
        fn serialize_i64(self, _: i64) -> Result<Self::Ok, Self::Error> {
            Err(serde::ser::Error::custom("not a struct variant"))
        }
        fn serialize_u8(self, _: u8) -> Result<Self::Ok, Self::Error> {
            Err(serde::ser::Error::custom("not a struct variant"))
        }
        fn serialize_u16(self, _: u16) -> Result<Self::Ok, Self::Error> {
            Err(serde::ser::Error::custom("not a struct variant"))
        }
        fn serialize_u32(self, _: u32) -> Result<Self::Ok, Self::Error> {
            Err(serde::ser::Error::custom("not a struct variant"))
        }
        fn serialize_u64(self, _: u64) -> Result<Self::Ok, Self::Error> {
            Err(serde::ser::Error::custom("not a struct variant"))
        }
        fn serialize_f32(self, _: f32) -> Result<Self::Ok, Self::Error> {
            Err(serde::ser::Error::custom("not a struct variant"))
        }
        fn serialize_f64(self, _: f64) -> Result<Self::Ok, Self::Error> {
            Err(serde::ser::Error::custom("not a struct variant"))
        }
        fn serialize_char(self, _: char) -> Result<Self::Ok, Self::Error> {
            Err(serde::ser::Error::custom("not a struct variant"))
        }
        fn serialize_str(self, _: &str) -> Result<Self::Ok, Self::Error> {
            Err(serde::ser::Error::custom("not a struct variant"))
        }
        fn serialize_bytes(self, _: &[u8]) -> Result<Self::Ok, Self::Error> {
            Err(serde::ser::Error::custom("not a struct variant"))
        }
        fn serialize_none(self) -> Result<Self::Ok, Self::Error> {
            Err(serde::ser::Error::custom("not a struct variant"))
        }
        fn serialize_some<T>(self, _: &T) -> Result<Self::Ok, Self::Error> where T: ?Sized + Serialize {
            Err(serde::ser::Error::custom("not a struct variant"))
        }
        fn serialize_unit(self) -> Result<Self::Ok, Self::Error> {
            Err(serde::ser::Error::custom("not a struct variant"))
        }
        fn serialize_unit_struct(self, _: &'static str) -> Result<Self::Ok, Self::Error> {
            Err(serde::ser::Error::custom("not a struct variant"))
        }
        fn serialize_unit_variant(self, _: &'static str, _: usize, _: &'static str) -> Result<Self::Ok, Self::Error> {
            Err(serde::ser::Error::custom("not a struct variant"))
        }
        fn serialize_newtype_struct<T>(self, _: &'static str, _: &T) -> Result<Self::Ok, Self::Error> where T: ?Sized + Serialize {
            Err(serde::ser::Error::custom("not a struct variant"))
        }
        fn serialize_newtype_variant<T>(self, _: &'static str, _: usize, _: &'static str, _: &T) -> Result<Self::Ok, Self::Error> where T: ?Sized + Serialize {
            Err(serde::ser::Error::custom("not a struct variant"))
        }
    }

    struct IdStructSerializer;
    impl serde::ser::SerializeStructVariant for IdStructSerializer {
        type Ok = usize;
        type Error = serde::ser::Error;
        fn end(self) -> Result<Self::Ok, Self::Error> {
            Err(serde::ser::Error::custom("not implemented"))
        }
        fn serialize_field<T>(&mut self, _: &'static str, _: &T) -> Result<(), Self::Error> where T: ?Sized + Serialize {
            Ok(())
        }
    }

    message.serialize(IdSerializer).unwrap()
}

注:若不需要手动获取变体ID,send函数可简化为直接返回序列化后的字节流——borsh已将变体ID编码在字节流头部。

二、手动实现序列化/反序列化(完全掌控逻辑)

如果需要自定义序列化规则,可手动处理变体ID和字节转换:

步骤1:定义消息Trait与枚举

// 通用消息Trait
trait NetworkMessage: Sized {
    fn serialize(&self) -> Vec<u8>;
    fn deserialize(data: &[u8]) -> Result<Self, &'static str>;
    fn variant_id(&self) -> usize;
}

// 消息枚举实现Trait
#[derive(Debug, Clone)]
enum Messages {
    Welcome,
    Position(f32, f32),
    Damages(u8),
}

impl NetworkMessage for Messages {
    // 序列化:写入变体ID+字段字节
    fn serialize(&self) -> Vec<u8> {
        let mut buf = Vec::new();
        match self {
            Messages::Welcome => buf.push(0x00),
            Messages::Position(x, y) => {
                buf.push(0x01);
                // 用大端字节序保证跨平台一致
                buf.extend_from_slice(&x.to_be_bytes());
                buf.extend_from_slice(&y.to_be_bytes());
            }
            Messages::Damages(dmg) => {
                buf.push(0x02);
                buf.push(*dmg);
            }
        }
        buf
    }

    // 反序列化:读取ID后匹配变体
    fn deserialize(data: &[u8]) -> Result<Self, &'static str> {
        if data.is_empty() {
            return Err("empty data");
        }
        let id = data[0];
        let rest = &data[1..];

        match id {
            0x00 => Ok(Messages::Welcome),
            0x01 => {
                if rest.len() != 8 {
                    return Err("invalid position data length");
                }
                let x = f32::from_be_bytes(rest[0..4].try_into().unwrap());
                let y = f32::from_be_bytes(rest[4..8].try_into().unwrap());
                Ok(Messages::Position(x, y))
            }
            0x02 => {
                if rest.len() != 1 {
                    return Err("invalid damages data length");
                }
                Ok(Messages::Damages(rest[0]))
            }
            _ => Err("unknown variant id"),
        }
    }

    // 返回变体ID
    fn variant_id(&self) -> usize {
        match self {
            Messages::Welcome => 0x00 as usize,
            Messages::Position(_, _) => 0x01 as usize,
            Messages::Damages(_) => 0x02 as usize,
        }
    }
}

步骤2:实现泛型发送/接收函数

fn send<E: NetworkMessage>(message: E) -> (Vec<u8>, usize) {
    (message.serialize(), message.variant_id())
}

fn message_received<E: NetworkMessage>(data: Vec<u8>) -> Result<E, &'static str> {
    E::deserialize(&data)
}

关键注意事项

  • 服务端与客户端必须使用完全一致的枚举定义(包括变体顺序、字段类型、ID映射),否则会出现序列化/反序列化错误。
  • 手动实现时务必保证字节序一致(推荐用大端字节序),避免跨平台兼容性问题。
  • 变体数量较多时,手动实现容易出错,优先选择成熟序列化库。

内容的提问来源于stack exchange,提问作者LucioleMaléfique

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 18:35:28