1、我的理解
在linux下写了多年的网络应用编程,一直copy&paste,今天突然发现对struct sockaddr、struct sockaddr_in、 struct in_addr这3个结构之间的关系还是模糊的,对什么时候该用哪个结构不清楚,惭愧啊。在此,翻阅了/usr/include下的头文件和阅读了一遍man手册,记录下来,权当对自己技术能力的反思。
1、struct sockaddr 结构:
typedef unsigned short int sa_family_t;
#define __SOCKADDR_COMMON(sa_prefix) \
sa_family_t sa_prefix##family
struct sockaddr
{
__SOCKADDR_COMMON (sa_); /* Common data: address family and length. */
char sa_data[14]; /* Address data. */
};
它定义在sys/socket.h头文件中,定义它的目的是:因为bind、accept等API的实现屏蔽掉具体的网络协议族,所以就需要定义出1个通用的结构作为API的参数。所以用户在使用不同的协议族时,需要将具体的协议族地址结构的指针转换成struct sockaddr结构指针(如示例)。但无论使用什么协议族,具体协议族地址结构的第一个字段必须是sa_family_t类型,表示本地址具体使用的协议族(参见struct sockaddr_in、struct sockaddr_in6结构)。
struct sockaddr_in ipv4_addr;
struct sockaddr *addr = (struct sockaddr*)&addr;
bind(sockfd, addr, sizeof(ipv4_addr));
2、struct sockaddr_in 结构:
typedef uint16_t in_port_t;
typedef uint32_t in_addr_t;
struct in_addr { in_addr_t s_addr; };
struct sockaddr_in {
sa_family_t sin_family;
in_port_t sin_port;
struct in_addr sin_addr;
uint8_t sin_zero[8];
};
它定义在netinet/in.h头文件中,它表示1个ipv4的地址,sizeof(struct sockaddr)与sizeof(struct sockaddr_in)刚好相等。
3、struct sockaddr_in6 结构:
struct in6_addr {
union {
uint8_t __s6_addr[16];
uint16_t __s6_addr16[8];
uint32_t __s6_addr32[4];
} __in6_union;
};
#define s6_addr __in6_union.__s6_addr
#define s6_addr16 __in6_union.__s6_addr16
#define s6_addr32 __in6_union.__s6_addr32
struct sockaddr_in6 {
sa_family_t sin6_family;
in_port_t sin6_port;
uint32_t sin6_flowinfo;
struct in6_addr sin6_addr;
uint32_t sin6_scope_id;
};
它定义在netinet/in.h头文件中,它表示1个ipv6的地址,虽然sizeof(struct sockaddr)小于sizeof(sockaddr_in6);一般不会使用struct sockaddr结构定义的变量,只会使用struct sockaddr结构定义的指针;所以只会涉及指针类型的强转。切记不可以将struct sockaddr_in6的变量直接赋值给struct sockaddr的变量;当然一般也不会定义struct sockaddr的变量。