结构体转字节流的分析浅析

本文介绍如何通过UDP协议传输结构体字节流,并详细解释了结构体字节计算方法,包括对string和int数组长度的限定及其原因。同时介绍了如何使用mscorlib.dll库中的Marshal方法来验证结构体的字节大小,以及客户端如何正确转换接收到的字节流。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在网络传输上常常会听到字节流传输数据个词,刚好最近公司接到一个利用UDP传输字节流的传输数据的的项目,他们公司传输的是一个结构体的的字节流数据,我们需要对传输过来的字节流的的接收和进行数据的转化。

这里我们就要了解什么事字节,字节是一种计算机的数据存储的计量单位,也白表示一些计算机编程语言中的数据类型以及语言字符。这样说可能很书面化的答案,在我们用电脑的时候常会说,1KB,1GB,1TB等,这里B就表示的Byte也就是我们常说的字节。

下面是百度的数据存储转化对应表:


那么如果我想传输结构体的数据的时候,就要涉及到对字节计算,只有在结构体和字节流的长度都正确的情况下转化才能正常完成。那么我们来简单的计算一下下面的字节大概是多少吧~

        public struct TestStruct
        {
            public int newint;
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 20)]
            public string newstr;
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
            public int[] test;
        }

上面的代码的总共32个字节,那么怎么计算出来的呢?

newint占用4个字节

newstr占用20个字节

test数组则是8个字节

有人肯定会问string为什么会20个字节是,test为什么是8个字节呢?这里原因很简单,我对结构体的string的字节长度进行了限制上面的 [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 20)]这句话就是对string长度进行了限制,同理int数字也是限制了长度2个。

这里肯定有人会问为啥要限制string和数字长度呢?

因为在数据传输中结构体转化byte中string会根据你真实的数据来判断是否要添加string的长度,导致客户端无法判断string正确占用多少字节,就会导致数据转化时候出问题了

int[]是应为这个原因导致数据转化出现错误和数据丢失的问题。

那么我们怎么验证结构体的字节计算时正确的呢?mscorlib.dll库为我们提供了Marshal法来计算结构体的字节大小方法,方法如图所示:

我们去验证一下字节数究竟对不对,下图为我断点调试的结果,如果所示:


结构体中字节数占用的32个字节,然后我申请一个句柄来存储结构体的数据,然后将句柄中的数据赋值给字节数组,然后是放句柄的就就可以了~

这样就达到了数据字节流的转化了。

那么传出过来的数据是字节流,也就表示客户端肯定需要转化数据后才能使用其结构体的数据,Marshal方法也为我们提供了byte数组转化方法了,这里我们只要调用就可以转化成结构体。

这里要注意的是客户端的结构体一定顺序一定要和服务端的一致不然转化数据的时候就会出问题的,还有的是一定要注意结构体的字节一定要和服务端一致,不然转化一定会出现数据错误甚至直接报错栈溢出等。

方法和结构体转化byte型一样,都是通过句柄进行中间的转化,通过句柄来转化结构体。代码如下图所示:


这里通过泛型来判断结构体,同样在进入转化的时候,我们先去判断结构体的字节是否和需要转化的字节数组对应的上。

最后看看调试转化后的效果,效果如下图所示:


但是我公司接到的数据并不是10进制的数据,而是16进制的,在byte数组里面可以详细看到数据是10进制的,这里需要用到10进制转16进制的方法。这里只要知道10怎么转化16进制就可以解决这个问题了。有时间我会将这个原理写出来。


这里要感谢天下的博文:点击打开链接

还有xiaobai1593的转载博文:点击打开链接 原文的作者并没有找到,但是还是非常感谢!!


如果有兴趣的孩子还在可以去试试将客户端的机构体换换顺序,你会发现意想不到的问题的~

要将一个复杂结构体换为字节流,你可以使用序列化的方式。序列化是将数据结构换为字节流的过程,以便在不同的系统或平台之间进行传输或存储。 在 C++ 中,你可以使用库来实现结构体的序列化,例如 Google 的 Protocol Buffers、Boost 库中的序列化机制等。下面以 Google 的 Protocol Buffers 为例,演示如何进行结构体的序列化。 首先,你需要定义一个 .proto 文件来描述你的数据结构。例如,假设你有一个学生结构体,包含学生的姓名、年龄和学号: ```proto syntax = "proto3"; message Student { string name = 1; int32 age = 2; int32 student_id = 3; } ``` 接下来,你需要使用 Protocol Buffers 的编译器将 .proto 文件编译为对应的 C++ 类。假设你将生成的类命名为 StudentMessage。 然后,在你的 C++ 代码中,你可以使用生成的类来创建一个学生对象,并将其序列化为字节流: ```cpp #include "student_message.pb.h" #include <fstream> int main() { // 创建一个学生对象 StudentMessage::Student student; student.set_name("Alice"); student.set_age(18); student.set_student_id(12345); // 将学生对象序列化为字节流 std::string serialized_data; student.SerializeToString(&serialized_data); // 将字节流写入文件 std::ofstream file("student.bin", std::ios::binary); file.write(serialized_data.c_str(), serialized_data.size()); file.close(); return 0; } ``` 在上述示例中,我们创建了一个 Student 对象,并设置了学生的姓名、年龄和学号。然后,使用 Student 对象的 SerializeToString() 函数将其序列化为字节流,并将字节流写入文件 "student.bin"。 当你想要从字节流中反序列化恢复结构体时,你可以使用相应的反序列化函数进行操作。 希望这个示例能够帮助你理解如何使用序列化来将复杂结构体换为字节流。如果还有其他问题,请随时提问。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值