Linux内核如何处理TCP / IP堆栈上的结构填充?

时间:2015-06-24 01:47:23

标签: c sockets tcp linux-kernel ip

我对内核的套接字缓冲系统有点熟悉,我搜索了很多,但我一直无法找到内核如何处理struct padding的问题。内核如何打包传出TCP / IP数据包的字节,以便在不同平台上运行的代码可以理解它?

将数据从一台机器发送到另一台机器时,我知道您不能按原样发送结构。然而,这就是Linux内核中的代码所发生的事情。我错过了什么?

1 个答案:

答案 0 :(得分:2)

由于你没有引用特定的代码,我只能谈论一般事情。

  

我搜索了很多,但我一直无法找到内核如何处理   struct padding的问题。

GCC提供了确保struct成员之间没有填充的机制。一种这样的机制是packed属性。这样你就可以定义一个结构,并确切地知道结构的内存布局。

  

内核如何打包传出TCP / IP数据包的字节   在不同平台上运行的代码可以理解它吗?

TCP / IP定义TCP和IP标头的内存布局。您可以在here找到相关信息。

  

从一台机器发送数据到另一台机器时,我知道你不能只是   按原样发送你的结构。

实际上,你可以,你必须非常谨慎地对待你的工作方式,基本上就是Linux。只是通过TCP套接字将结构发送到具有相同结构定义的另一个程序是危险的,原因有几个。采用以下结构:

struct my_struct {
    uint32 foo;
    uint64 bar;
}

人们说你不应该只发送一个结构的一个原因是这个结构的内存布局可能在不同的机器上或不同的编译器上有所不同。例如,在32位机器上可能没有任何填充,在64位机器上,它们可能是foobar之间的32位填充。我使用可能可能这样的词,因为编译器不会被强制添加填充;它只是一个可能做的优化。即使机器都是64位,如果你使用不同的编译器,你可能会得到不同的结果,因为不同的编译器可能会添加或不添加填充。还有endianness的问题,所以如果你在一个小端机器上,你应该转换为大端,因为这是指定的网络字节顺序。另一个需要考虑的问题是,我的例子不是,某些类型将具有不同的大小,同样取决于编译器和体系结构。因此,例如size_t可能是32位机器上的32位和64位机器上的64位。因此,不同机器上的相同代码将生成不同大小的结构。但是,如果您使用具有特定位宽的类型,如我的示例所示,这不是问题。

现在,如果您处理Linux内核所做的所有问题,那么可以只发送一个结构。

有关通常通过TCP发送结构的原因的更多信息,this SO question可能有用。正如现在的最佳答案所述,有三个主要原因(我在此概述的相同),但如果你照顾它们,它是可能的。虽然在某些时候用户空间程序可能不是一个好习惯,因为诸如TCP数据包之类的东西有特定的字段要求。