1.字节序
不同体系结构的主机使用不同的字节序存储器保存多字节整数。字节序存储顺序不同,有的系统高位在前,低位在后(大端字节序),而有的系统是低位在前,高位在后(小端字节序)。
以32位存储为例:
网络中协议中使用的网络字节序高位在前,低位在后,也就是大端字节序。因此,如果计算机存储的字节序与网络字节序不一致的话,需要进行字节序的转换。
下面是不同长度的整数网络字节序与主机字节序直接转换的函数(会根据主机字节序是大端还是小端,完成转换):
将一个32位的整数由主机字节序转换为网络字节序
uint32_t htonl(uint32_t hostlong);
将一个16位的整数由主机字节序转换为网络字节序
uint16_t htons(uint16_t hostshort);
将一个32位的整数由网络字节序转换为主机字节序
uint32_t ntohl(uint32_t netlong);
将一个16位的整数由网络字节序转换为主机字节序
uint16_t ntohs(uint16_t netshort);
2. 地址结构
通用地址结构
#include <sys/socket.h> struct sockaddr { unsigned short sa_family; /*Internet 地址族,AF_XXX*/ char sa_data[14]; /*14字节的协议地址*/ };
sa_family指定地址族的类型,比如IPV4地址族为AF_INET
sa_data包含了一些远程电脑的地址、端口和套接字的数目,它里面的数据是杂容灾一起的。
这种通用地址结构比较复杂,我们一般会使用专用的因特网地址结构(下面会介绍),但是在将专用的因特网地址结构传递给需要地址结构的函数时,需要把专用的因特网地址结构强制转换成通用地址结构再传递进函数。
因特网地址结构
struct in_addr { in_addr_t s_addr /*IPV4地址*/ }; struct sockaddr_in { short int sin_family; /*internet 地址族如AF_INET(主机字节序)*/ unsigned short int sin_port; /*端口号,16位值(网络字节序)*/ struct in_addr sin_addr; /*internet地址,32位IPV4地址(网络字节序,非点分十进制形式)*/ unsigned char sin_zero[8]; /*写0(为了格式对齐的填充位)*/ };
注意:因特网地址结构在使用的时候最终需要强制转换为通用地址结构。
IPV4地址族和字符地址间的转换(网络字节序与点分十进制间的转换)
#include <arp/inet.h> const char *inet_ntop(int domain, const void *restrict addr, char *restrict str, socklen_t size);
返回:成功返回地址字符串指针,出错返回NULL
功能:网络字节序转换为点分十进制
int inet_pton(int domain, const char* restrict str, void *restrict addr);
返回:成功返回1,无效格式返回0,出错返回-1
功能:点分十进制转换为网络字节序
参数:
domain,internet地址族,如AF_INET
addr,internet地址,32位IPV4地址(网络字节序)
str:地址字符串(点分十进制)指针
size:地址字符串str的大小
填写IPV4地址族结构案例
struct sockaddr_in sin; /*定义一个sockaddr_in结构体(专用地址结构)*/ char buf[16]; memset(&sin, 0, sizeof(sin));/*内存清理*/ sin.sin_family = AF_INET; /*填写Internet地址族*/ sin.sin_port = htons((short)3001); /*填写端口(网络字节序)*/ if(inet_pton(AF_INET, "192.168.1.5", &sin.sin_addr.s_addr) < 0) { //错误处理 } print(“%s\n”, inet_ntop(AF_INET, &sin.sin_addr.s_addr, buf, sizeof(buf)))