int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
为addr参数传递的实际结构将取决于地址族。 sockaddr结构定义为:
struct sockaddr {
sa_family_t sa_family;
char sa_data[14];
}
因此,对于IPv4地址(AF_INET),将传递的实际结构是:
/* Source http://linux.die.net/man/7/ip */
struct sockaddr_in {
sa_family_t sin_family; /* address family: AF_INET */
in_port_t sin_port; /* port in network byte order */
struct in_addr sin_addr; /* internet address */
};
/* Internet address. */
struct in_addr {
uint32_t s_addr; /* address in network byte order */
};
绑定代码是否读取sockaddr.sa_family
值并根据它找到的值,然后将sockaddr
结构转换为适当的结构,例如sockaddr_in
?
为什么sa_data
设置为14个字符?如果我理解正确,sa_data
字段只是一个具有足够大的内存空间以适合所有地址族类型的字段?据推测,原始设计师预计14个字符的宽度足以适应所有未来类型。
答案 0 :(得分:5)
根据glibc manual:
sa_data的长度14基本上是任意的。
FreeBSD developers handbook提及以下内容:
请注意声明sa_data字段的模糊性, 就像一个14字节的数组一样,注释暗示可以 其中超过14个。
这种含糊不清是非常刻意的。套接字非常强大 接口。虽然大多数人可能认为它只不过是 互联网接口 - 大多数应用程序可能会使用它 nowadays-socket可以用于几乎任何类型的进程 通信,其中只有互联网(或更确切地说是IP) 之一。
是的,sa_family
字段用于识别如何处理传递的结构(在绑定调用中强制转换为struct sockaddr*
)。您可以在FreeBSD developers handbook。
实际上有"多态" (子)sockaddr
的类型,其中sa_data
包含超过16个字节,例如:
struct sockaddr_un {
sa_family_t sun_family; /* AF_UNIX */
char sun_path[108]; /* pathname */
};
答案 1 :(得分:3)
sockaddr
结构用作标记联合。通过阅读sa_family
字段,可以将其转换为正确形式的结构。
14个字节是任意的。它足以容纳IPv4地址,但不足以容纳IPv6地址。还有一个sockaddr_storage
结构,对于两者都足够大。阅读SOCKADDR_STORAGE上的Microsoft文档,它以128字节为单位,比IPv6所需的大得多。检查一些Linux标题,它似乎至少也是那么大。
作为参考,IPv6结构是:
struct sockaddr_in6 {
u_int16_t sin6_family; // address family, AF_INET6
u_int16_t sin6_port; // port number, Network Byte Order
u_int32_t sin6_flowinfo; // IPv6 flow information
struct in6_addr sin6_addr; // IPv6 address
u_int32_t sin6_scope_id; // Scope ID
};
struct in6_addr {
unsigned char s6_addr[16]; // IPv6 address
};
如您所见,16字节s6_addr
字段已经大于它自己的14字节sa_data
字段。 sa_family
字段后的总大小为26个字节。