二进制协议 - 字节交换技巧

时间:2009-03-14 22:20:15

标签: c++ c

假设我们有一个二进制协议,字段网络有序(大端)。

struct msg1
{
    int32 a;
    int16 b;
    uint32 c
}

如果不是将网络缓冲区复制到我的msg1然后使用“networkToHost”函数来读取msg1

我重新排列/反转msg1到

struct msg1
{
    uint32 c
    int16 b;
    int32 a;
}

只需从网络缓冲区执行反向复制即可创建msg1。在这种情况下,不需要networkToHost功能。这种习惯用法在大端机器上不起作用,但对我来说这不是问题。除此之外,我还有其他任何缺点吗?

感谢

P.S。对于上面我们强制执行严格的对齐(#pragma pack(1)等)

7 个答案:

答案 0 :(得分:20)

除此之外,我还有其他任何缺点吗?

我担心你误解了endian转换问题的本质。 “大端”并不意味着你的字段反向布局,所以

struct msg1_bigendian
{
    int32 a;
    int16 b;
    uint32 c
}
大端架构上的

等同于

struct msg1_littleendian 
{
   uint32 c;
   int16 b;
   int32 a;
}

在一个小端架构上。相反,它意味着每个字段中的字节顺序是相反的。我们假设:

a = 0x1000000a;
b = 0xb;
c = 0xc;

在大端架构上,这将被描述为:

10 00 00 0a
00 0b
00 00 00 0c

首先是高阶(最重要)字节。

在小端机器上,这将被布置为:

0a 00 00 10
0b 00
0c 00 00 00

最低位字节排在第一位,最后一位是最后一位。

序列化它们并将消息的序列化形式叠加在一起,您将发现不兼容性:

10 00 00 0a  00 0b  00 00 00 0c (big endian)
0a 00 00 10  0b 00  0c 00 00 00 (little endian)

   int32 a  int16 b    int32 c

请注意,这不仅仅是字段反向运行的情况。你的提议会导致一个小端的机器将大端表示误认为:

a = 0xc000000;   b = 0xb00;   c = 0xa000010;

当然不是传播的内容!

对于每个传输的字段,您确实必须将每个字段转换为网络字节顺序并再次返回。

更新:

好的,我明白你现在要做什么。你想要反向定义结构,然后从字节串的 end 到开头的memcpy(反向复制),并以这种方式反转字节顺序。在这种情况下,我会说,是的,这是一个黑客,是的,它使你的代码不可移植,是的,它是不值得的。事实上,在字节顺序之间进行转换并不是一项非常昂贵的操作,并且它比处理每个结构的布局要容易得多。

答案 1 :(得分:6)

你确定这是必需的吗?很可能,您的网络流量将成为您的瓶颈,而不是CPU速度。

答案 2 :(得分:5)

同意@ribond -

这对开发人员来说非常容易混淆,因为他们必须努力将这些与语义相同的结构分开。

鉴于网络延迟比CPU处理它的速度快10,000,000倍,我只是保持不变。

答案 3 :(得分:2)

根据编译器如何打包结构中的字节,中间的16位数字可能不会在正确的位置结束。它可能存储在32位字段中,当您反转字节时,它将“消失”。

说真的,这样的技巧在你写它们时看起来很可爱,但从长远来看它们根本就不值得。

修改

您添加了“打包1”信息,因此错误消失但关于“可爱技巧”的事情仍然存在 - 不值得。写一个函数来反转32位和16位数字。

inline void reverse(int16 &n)
{
  ...
}

inline void reverse(int32 &n)
{
  ...
}

答案 4 :(得分:1)

除非您能证明存在显着的性能损失,否则您应该使用相同的代码将数据传输到网络或从网络传输数据,而不管机器的字节顺序如何。作为优化,对于网络顺序与硬件字节顺序相同的平台,您可以使用技巧,但要记住对齐要求等。

在这个例子中,许多机器(尤其是大型机器)将需要在int16成员的末尾和下一个int32成员之间使用2字节的填充。因此,虽然您可以读入10字节的缓冲区,但您不能将该缓冲区视为结构的图像 - 在大多数平台上将为12字节。

答案 5 :(得分:1)

正如你所说,这对大端机器来说是不可移植的。如果您希望您的代码在x86世界之外使用,那么这绝对是一个绝对破坏者。让我们其他人一个忙,只需使用ntoh / hton例程,或者你可能会发现自己在thedailywtf上有特色。

答案 6 :(得分:0)

请为您提供帮助的程序员,并在某个缓冲区中对字节序列进行显式转换。带结构的诡计将引导你直接进入字节序和对齐地狱(在那里)。