套接字地址结构为什么分 IPv4 IPv6 通用三种?

在套接字编程中, 一个网络连接的两端是通过套接字标识的,
而套接字的内容包括通信两端主机的 IP 地址和端口号、协议族等填充。
这些内容需要保存在对应协议的套接字地址结构中,比如

IPv4 的套接字地址结构,定义在<\netinet/in.h>:

struct sockaddr_in{
    uint8_t         sin_len;  // length of structure: 16
    sa_family_t     sin_family; // AF_INET
    in_port_t       sin_port; // 16-bit TCP or UDP port number, network ordered
    struct in_addr  sin_addr; // 32-bit IPv4 address, network ordered
    char            sin_zero[8]; // unused
}

struct in_addr{
    in_addr_t       s_addr; // 32-bit IPv4 address, network byte ordered
}

IPv6 的套接字地址结构,定义在<\netinet/in.h>:

#define SIN6_LEN
struct sockaddr_in6{
    uint8_t         sin6_len;  // length of structure: 28
    sa_family_t     sin6_family; // AF_INET6
    in_port_t       sin6_port; // transport layer port, network ordered
    uint32_t        sin6_flowinfo // flow information, undefined
    struct in6_addr sin6_addr; // IPv6 address, network ordered
    uint32_t        sin6_scope_id; // set of interfaces for a scope
}

struct in6_addr{
    uint8_t         s6_addr[16]; // 128-bit IPv6 address, network byte ordered
}

那为什么会需要一个通用套接字地址结构?分析如下:
套接字函数的套接字地址结构参数是以指针形式传入,比如
int bind(int, struct sockaddr *, socklen_t);
而不同协议(IPv4,IPv6)的地址结构类型不同,因此为了兼容两者必须使用一个统一的类型,一般情况下我们可以使用 void * 类型来作为这些套接字函数的入参(在网络编程的时候直接将特定协议的套接字地址结构强制转换为 void ),但是 void 类型是在 ANSI C 标准中定义的,而套接字函数的定义早于 ANSI C 标准,因此只能单独定义一个通用套接字类型来兼容多个协议类型。
通用套接字地址结构,定义在<\sys/socket.h>:

struct sockaddr{
    uint8_t       sa_len;
    sa_family_t   sa_family; // address family: AF_xxx value
    char          sa_data[14]; // protocol-specific address
}

最新通用套接字地址结构,定义在<\netinet/in.h>:

struct sockaddr_storage{
    uint8_t       ss_len; // length of this struct: implementation dependent
    sa_family_t   ss_family; // address family: AF_xxx value
}

很明显,在使用这些套接字函数是我们需要强制转换特定协议的套接字地址结构为通用套接字地址结构。

猜你喜欢

转载自blog.csdn.net/chuanglan/article/details/80682948