我用谷歌搜索了一些人说“要与struct sockaddr保持相同的大小”。但内核不会直接使用sockaddr(对吧?)。使用时。内核会把它重新归结为它。那么为什么需要零填充?
struct sockaddr {
unsigned short sa_family; // address family, AF_xxx
char sa_data[14]; // 14 bytes of protocol address
};
struct sockaddr_in {
short sin_family; // e.g. AF_INET, AF_INET6
unsigned short sin_port; // e.g. htons(3490)
struct in_addr sin_addr; // see struct in_addr, below
char sin_zero[8]; // zero this if you want to
};
struct in_addr {
unsigned long s_addr; // load with inet_pton()
};
答案 0 :(得分:10)
我能找到的两个更相关的信息是
谈论不清除字节
的代码片段这是一个错误。我发现偶尔会发生这种情况。此错误可能导致应用程序中的未定义行为。
接下来的一些说明
大多数网络代码不使用sockaddr_in,它使用sockaddr。当您使用像sendto这样的函数时,您必须显式地将sockaddr_in或您使用的任何地址转换为sockaddr。 sockaddr_in与sockaddr的大小相同,但内部大小相同,因为有轻微的黑客攻击。
那个黑客是sin_zero。实际上sockaddr_in中有用数据的长度比sockaddr短。但是使用一个小缓冲区在sockaddr_in中填充差异;缓冲区是sin_zero。
最后,可以在各个地方找到的信息
在某些架构上,它不会导致任何不清除sin_zero的问题。但在其他架构上它可能会。规范要求清除sin_zero,所以如果你打算现在和将来你的代码都没有bug,你必须这样做。
回答问题
为什么我们需要这个8字节的填充?
和答案
Unix网络编程3.2章说“POSIX规范 在结构中只需要三个成员:sin_family,sin_addr和 sin_port。符合POSIX的实现可以定义 其他结构成员,这对于Internet套接字地址是正常的 结构体。几乎所有实现都添加了sin_zero成员以便所有套接字 地址结构的大小至少为16个字节。 “
它有点像结构填充,可能保留给中的额外字段 未来。你将永远不会使用它,就像评论一样。
与第一个链接一致。清除字节告诉接收者“我们这边没有使用那些字节”。
答案 1 :(得分:2)
由于struct sockaddr_in需要强制转换为struct sockaddr,因此它必须保持相同的大小,sin_zero是一个未使用的成员,其唯一目的是将结构填充到16个字节(sock_addr的大小)。此填充大小可能因地址系列而异。例如;
struct sockaddr_in {
short int sin_family; // Address family, AF_INET
unsigned short int sin_port; // Port number
struct in_addr sin_addr; // Internet address
unsigned char sin_zero[8]; // For padding, to make it same size as struct sockaddr
};
现在选择具有不同结构成员的Xerox NS系列:
struct sockaddr_ns {
u_short sns_family; // Address family, AF_NS
struct ns_addr sns_addr; // the 12-byte XNS address
char sns_zero[2]; // unused except for padding
};
答案 2 :(得分:0)
发生结构填充是因为结构的成员必须出现在Correce字节边界,为此,编译器会填充填充字节(如果正在使用位字段,则为bit),以便结构成员出现在正确的位置。另外,结构的大小必须使得在结构的阵列中所有结构在存储器中正确对准。
因此,可能需要忽略内存泄漏。
答案 3 :(得分:0)
struct sockaddr
是此结构的抽象,不完整版本,只有该系列。 struct sockaddr_in
是此结构的IPv4版本。它只使用前8个字节。 struct sockaddr_in6
是此结构的IPv6版本,并且更大。填充允许较小的结构以适应该结构的最大变化,因此缓冲区不会过小。
当您将地址传递给函数或系统调用时,额外的字节不是必需的。但是检索地址时,您需要为结果提供结构地址。该结构需要是所有可能变化中最大的。如果不是 - 想象你提供了一个IPv4版本,但得到了一个IPv6地址 - 那么结果将超出结构并破坏内存中的隔壁。
为避免此内存损坏,大多数相关函数将结构大小作为参数。但现在,当您传递IPv4版本及其太小的尺寸时,您最终会得到一个未完全填充的IPv6版本的结构。看看这个家庭,你可以看到它是IPv6。但是,如果将结构转换为IPv6并尝试使用它,则内容错误,因为结构太小而无法包含完整有效的数据。
填充较小的结构可以避免这些障碍,并避免任何相关的潜在安全问题。