将一些数据写入 Char

发布于 2025-01-05 21:37:43 字数 330 浏览 2 评论 0原文

还有一些网络问题。我偶然发现了这个问题: 结构的序列化/反序列化到 C 中的 char* ,很多答案都是有道理的,但我一遍又一遍地看到的是所有数据包似乎都携带的“字符数据”字段。

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

some more networking problems. I stumbled into this question: Serialization/Deserialization of a struct to a char* in C and a lot of the answers are making sense, but what I keep seeing over and over again is this 'char data' field that all packets seem to carry.

Now i know what it is for - you store the data you want to send in here. But how does one actually write data to it? Is there ways to just store entire objects in this data field? Or do i somehow serialize the object, store it in data, and then serialize the packet before i send everything off..?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

对岸观火 2025-01-12 21:37:43

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

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

因此,如果我声明:

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

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

 xyzzqqqq

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

因此,该对象已经“序列化” - 您有一堆表示它的字节。这就是您需要通过网络发送的全部内容:表示数据结构的信息。

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

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

更具体地说,将数据放入数据包的“char data”字段的方式是通过从数据当前所在的位置进行memcpy到缓冲区中。因此,如果我有一个 char* 目标,我可以这样写入一个 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 内的某个偏移量,并写入等于成员变量表示形式长度的字节数。

对您上一个问题的接受答案指出,这是一个过于简单化的问题:当您通过网络发送多字节整数时,您必须担心字节顺序(字节顺序)。因此,您实际要做的是:

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

这将适当地反转字节,以从主机字节顺序转换为网络字节顺序。显然,一字节长的值是免疫的。

Every variable exists in your computer's memory. The memory is organized in bytes.

When you're writing C++ code, you can directly read those bytes. For a struct, the memory for all of its members is in one contiguous chunk (although there may be gaps between each member).

So, if I declare:

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

Then when I create a struct foo, I get the following layout in memory (8 total bytes on most systems):

 xyzzqqqq

The first byte is x, the second y, the third and fourth together are z, and the last four are q.

So, the object is already "serialized" - you have a bunch of bytes which represent it. That's all you need to send over the network: the information which represents the data structure.

The reason you'd write your own serializer is because you might want to change the way that the object is read or written (for instance, what if I added a field to struct foo?), because you need to communicate between machines where the memory layout is different (which byte of z represents the "most significant" portion of the number?), or because you only want to serialize part of the structure (what if we had some empty space between the members?).

But, fundamentally, the reason you're sending "char data" is because everything in your computer can be represented that way. I'm not going into Turing's proofs about symbol encoding, but it's a mathematical certitude that any piece of knowledge can be encoded as a series of ones and zeroes.

In more concrete terms, the way you put data into the "char data" field of a packet is by memcpying from where the data currently are into the buffer. So if I had a char* target, I could write a struct foo x into it thusly:

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

Or I could do it more carefully by writing each field:

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));

The & is the address-of operator, if you didn't already know. So I'm writing from the address of each member, into some offset within target, and writing a number of bytes equal to the length of the member variable representation.

The accepted answer to your last question pointed out that this is an oversimplification: when you send a multibyte integer over the network, you have to worry about the endianness (byte order). So what you actually do is this:

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

This will handle reversing the bytes as appropriate to convert from host byte order to network byte order. Obviously the one-byte-long values are immune.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文