套接字地址结构
大多数套接字函数都需要一个指向套接字地址结构的指针作为参数。每个协议族都定义它自己的套接字地址结构。这些结构的名字均以sockaddr_ 开头,并以对应每个协议族的唯一后缀结尾。
1、IPv4套接字地址结构
IPv4套接字地址结构通常也称为“网际套接字地址结构”,它以sockaddr_in命名,定义在<netinet/in.h>头文件中。它的POSIX定义如下:
struct in_addr{
in_addr_t s_addr; //32-bit ipv4 address, network byte ordered
};
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 byte ordered
struct in_addr sin_addr; //32-bit ipv4 address, network byte ordered
char sin_zero[8];
};
1)IPv4地址和TCP或UDP端口号在套接字地址结构中总是以网络字节序来存储。
2)32位IPv4地址存在两种不同的访问方法。举例来说,如果serv定义为某个网际套接字地址结构,那么serv.sin_addr将按in_addr结构引用其中的32位IPv4地址,而serv.sin_addr.s_addr将按in_addr_t(通常是一个无符号的32位整数)引用同一个32位IPv4地址。因此必须正确使用IPv4地址,尤其是在将它作为函数参数时,因为编译器对传递结构和传递整数的处理是完全不同的。
sin_addr字段是一个结构,而不仅仅是一个in_addr_t类型的无符号长整数,这是有历史原因的。早期的版本(4.2BSD)把in_addr结构定义为多种结构的联合(union),允许访问一个32位IPv4地址中的所有4个字节,或者访问它的2个16位值。如今大多数系统已经废除了该联合,转而把in_addr定义为仅有一个in_addr_t字段的结构。
2、通用套接字地址结构
当作为一个参数传递进任何套接字函数时,套接字地址结构总是以引用形式(也就是以指向该结构的指针)来传递。然而以这样的指针作为参数之一的任何套接字函数必须处理来自所支持的任何协议族的套接字地址结构。
采取的办法是在<sys/socket.h>头文件中定义一个通用的套接字地址结构。如下所示:
struct sockaddr{
uint8_t sa_len;
sa_family_t sa_family;
char sa_data[14];
};
于是套接字函数被定义为以指向某个通用套接字地址结构的一个指针作为其参数之一。要求对这些函数的任何调用都必须要将指向特定协议的套接字地址结构的指针进行类型强制转换,变成指向某个通用套接字地址结构的指针。eg: bind(sockfd, (struct sockaddr *)&serv, sizeof(serv));
从应用程序开发人员的观点看,这些通用套接字地址结构的唯一用途就是对指向特定协议的套接字地址结构的指针执行类型强制转换。