套接字地址结构
大多数套接字函数都需要一个指向套接字地址结构的指针作为参数。每个协议定义有属于自己的套接字地址结构,均以“sockaddr_”开头。
例如:
- IPv4套接字地址结构以 “ sockaddr_in ”命名
- IPv6套接字地址结构以 " sockaddr_in6 ” 命名
1. IPV4地址结构
IPv4套接字地址结构以sockaddr_in命名,定义在<netinet/in.h>头文件中。下面给出了POSIX定义。
先定义一个结构体用来表示32位IPv4地址:
struct in_addr{
in_addr_t s_addr;//用来表示32位IPv4地址
};
in_addr_t 一般为 32位的unsigned int,其字节顺序为网络顺序(network byte ordered),即该无符号整数采用大端字节序。其中中每8位代表一个IP地址位中的一个数值。例如192.168.3.144记为0x 90 03 a8 c0,其中 c0 为192 ,a8 为 168, 03 为 3 , 90 为 144。打印的时候调用inet_ntoa()函数将其转换为char *类型。
struct sockaddr_in{
uint8_t sin_len;/*为了增加OSI协议支持增加的,简化了长度可变套接字地址结构处理 */
sa_family_t sin_family;/*地址族 AF_INET*/
in_port_t sin_port; /*16位TCP or UDP端口号*/
struct in_addr sin_addr; /*32位IP地址*/
char sin_zero[8];/* 未使用,置为0*/
};
sin_len字段表示结构体的长度,并不是所有的厂家都支持这个字段,而且POSIX规范也不要求有这个成员,所以即使有了长度字段,在Socket编程中也无需检测和设置这个字段,除非涉及路由套接字(由处理来自不同协议族的套接字地址结构的例程(如路由表处理代码)在内核中使用)。POSIX规范只需要s_addr,sin_family和sin_port这三个字段,但是几乎所有实现都增加了sin_zero字段,所以套接字地址结构大小都是至少16个字节。
in_addr_t数据类型是一个至少32位的无符号整数类型,in_port_t必须是一个至少16位的无符号整数类型,而sa_family_t可以是任何无符号整数类型,在支持长度字段的实现中,sa_family_t通常是一个8位的无符号整数,在不支持长度的字段实现中,则是一个长度为16位的无符号整数。
IPv4地址和TCP或UDP端口号在套接字地址结构中总是以网络字节序来存储。
32位的IPv4地址存在两种不同的访问方法。例如,若serv定义位某个网络套接字地址结构,那么serv.sin_addr将按in_addr结构引用其中的32位IPv4地址,而serv.sin_addr.s_addr将按in_addr_t(通常是一个无符号32位整数)来引用同一个32位IP地址。因此我们必须正确地使用IPv4地址,尤其是在将它作为函数的参数时,因为编译器对传递结构和传递整数的处理是完全不同的。
POSIX定义的一些数据类型如下:
2. IPV6地址结构
struct in6_addr {
uint8_t s6_addr[16];/*Ipv6的128位地址*/
}
#define SIN6_LEN
struct sockaddr_in6 {
uint8_t sin6_len;/*结构体长度*/
sa_family_t sin6_family;/*协议族*/
in_port_t sin6_port;/*端口,网络字节序*/
uint32_t siin6_flowinfo;/*分成两个字段,低序20位是流标,高序12位保留*/
struct in6_addr sin6_addr;/*IPv6的128位地址,网络字节序*/
uint32_t sin6_scope_id; /*标识具备范围的地址,最常见的是链路局部地址的结构索引*/
}
注:如果系统支持套接字地址结构,那么SIN6_LEN常值必须定义。