【问题标题】:Write some data to a Char将一些数据写入 Char
【发布时间】:2012-02-16 05:05:52
【问题描述】:

还有一些网络问题。我偶然发现了这个问题:Serialization/Deserialization of a struct to a char* in C,很多答案都很有道理,但我一遍又一遍地看到的是所有数据包似乎都携带的这个“字符数据”字段。

现在我知道它的用途了——你将要发送的数据存储在这里。但是如何实际向其写入数据呢?有没有办法将整个对象存储在这个数据字段中?或者我是否以某种方式序列化对象,将其存储在数据中,然后在发送所有内容之前序列化数据包..?

【问题讨论】:

    标签: c++ serialization udp char packets


    【解决方案1】:

    每个变量都存在于您计算机的内存中。内存以字节为单位。

    当您编写 C++ 代码时,您可以直接读取这些字节。对于一个结构,其所有成员的内存都在一个连续的块中(尽管每个成员之间可能存在间隙)。

    所以,如果我声明:

    struct foo {
        char x;
        char y;
        short z;
        int q;
    };
    

    然后,当我创建 struct foo 时,我在内存中得到以下布局(在大多数系统上总共 8 个字节):

     xyzzqqqq
    

    第一个字节是x,第二个字节是y,第三个和第四个一起是z,最后四个是q

    所以,对象已经“序列化”了——你有一堆代表它的字节。这就是您需要通过网络发送的全部内容:代表数据结构的信息。

    您编写自己的序列化程序的原因是您可能想要更改对象的读取或写入方式(例如,如果我向struct foo 添加一个字段会怎样? ),因为您需要在内存布局不同的机器之间进行通信(z 的哪个字节代表数字的“最重要”部分?),或者因为您只想序列化结构的一部分(如果我们成员之间有一些空白空间吗?)。

    但是,从根本上说,您发送“char 数据”的原因是因为您计算机中的所有内容都可以以这种方式表示。我不会讨论图灵关于符号编码的证明,但任何知识都可以编码为一系列 1 和 0,这是一个数学上的确定。

    更具体地说,将数据放入数据包的“char data”字段的方式是通过memcpying 从数据当前放入缓冲区的位置。所以如果我有一个char* target,我可以这样写一个struct foo x

    memcpy(target, &x, sizeof(struct foo));
    

    或者我可以通过编写每个字段来更仔细地做到这一点:

    memcpy(target, &x.x, 1);
    memcpy(target+1, &x.y, 1);
    memcpy(target+2, &x.z, sizeof(short));
    memcpy(target+4, &x.q, sizeof(int));
    

    & 是地址运算符,如果您还不知道的话。所以我从每个成员的地址开始写入target 内的某个偏移量,并写入等于成员变量表示长度的字节数。

    对您最后一个问题的公认答案指出,这是一种过度简化:当您通过网络发送多字节整数时,您必须担心 endianness(字节顺序)。所以你实际做的是:

    memcpy(target, &x.x, 1);
    memcpy(target+1, &x.y, 1);
    *((short*)(target+2)) = htons(x.z);
    *((int*)(target+4)) = htonl(x.q);
    

    这将根据需要处理反转字节以将主机字节顺序转换为网络字节顺序。显然,一字节长的值是免疫的。

    【讨论】:

    • C++ Middleware Writer 涵盖了您在此处描述的领域。
    • 和“读取”这些数据,一旦我确认它的类型,将是从 char 目标执行 memcpy 到(比如说)一个变量,它是所需结构/类的类型?所以 "foo* 复制X; memcpy(copiedX, &target, sizeof(struct foo)); "
    • 只是另一个问题,让我们说而不是 struct 'Foo' 我将在缓冲区中存储一个字符串。 'memcpy(目标, &somestring, sizeof(string));'真的不行吗?因为字符串可以有不同的大小。我会改用 sizeof(somestring) 吗?
    • @Prodigga 对于您的第一个问题,应该是memcpy(&copiedX, target, sizeof(struct foo));,因为target 已经是char*。第二,您不直接存储std::string。相反,您存储通过调用c_str() 获得的char* 并使用size() 来确定长度。恢复它时,您首先会看到传入数据使用strlen 的时长(或通过显式使用数据包中的长度字段)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多