期望指针的函数struct sockaddr
可能会在您向它们sockaddr
发送指向struct sockaddr_storage
. 这样,他们就可以像访问它一样访问它struct sockaddr
。
struct sockaddr_storage
被设计成同时适合一个struct sockaddr_in
和struct sockaddr_in6
您不会创建自己的struct sockaddr
,通常会根据您使用的 IP 版本创建一个struct sockaddr_in
或一个。struct sockaddr_in6
为了避免试图知道您将使用哪个 IP 版本,您可以使用struct sockaddr_storage
其中一个可以保存的。这将依次struct sockaddr
由 connect()、bind() 等函数进行类型转换并以这种方式访问。
您可以在下面看到所有这些结构(填充是特定于实现的,用于对齐目的):
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 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 sockaddr_storage {
sa_family_t ss_family; // address family
// all this is padding, implementation specific, ignore it:
char __ss_pad1[_SS_PAD1SIZE];
int64_t __ss_align;
char __ss_pad2[_SS_PAD2SIZE];
};
如您所见,如果函数需要 IPv4 地址,它将只读取前 4 个字节(因为它假定结构的类型为struct sockaddr
。否则它将读取 IPv6 的完整 16 个字节)。