1.字节顺序和转换函数
先来了解一个概念:大端模式和小端模式 大端模式是指高字节数据存放在低地址处,低字节数据存放在高地址处. 小端模式是指低字节数据放在内存的内存低地址处,高字节数据存放在内存的高地址处. 在网络上传输数据时,由于数据传输的两端可能对应不同的硬件平台,采用的存储字节的顺序也可能不一致,因此TCP/IP协议规定了在网络上必须采用网络字节顺序(大端模式),对于char 型数据,由于其只占一个字节,所以不存在这个问题,所以一般都把缓冲区定义成char 型,而对于IP地址等非char型的数据, 必须在数剧发送到网络前将其转换成大端,在接收数据前 再将其转换成符合接收端主机的存储模式. linux 下有4个大小端的转换函数. #include <netinet/in.h> uint32_t htonl(uint32_t hostlong); uint16_t htons(uint16_t hostshort); uint32_t ntohl(uint32_t netlong); uint16_t ntohs(uint16_t netshort); htonl表示host to network long:用于将主机unsigned int 型数据转换成网络字节顺序, htons表示host to network short:用于将主机unsigned short型数据转换为网络字节顺序 ntohl表示network to host long:用于就将网络unsigned int 型数据转换为主机的字节顺序. ntohs表示network to host short:用于将网络unsigned short 型数据转换为主机字节顺序.
2. inet系列函数
通常我们习惯用字符串形式的网络地址,然而在网络上进行数据通信时,需要使用的是二进制形式且为网络字节顺序的IP地址,linux 提供了一系列函数. #include <sys/socket.h> #include <netinet.h> #include <arpa/inet.h> int inet_aton(const char *cp,struct in_addr *inp); inet_aton()将参数cp所指的字符串形式的IP地址转换为二进制的网络字节顺序的IP地址,转换的结果保存在inp所指向的空间里.函数执行成功返回非0,失败返回0; in_addr_r inet_addr(const char*cp); inet_aton()将参数cp所指的字符串形式的IP地址转换为二进制的网络字节顺序的IP地址.执行成功返回转换后的结果,参数无效返回INADDR_NONE,该函数已经过时, in_addr_t inet_network(const char *cp); inet_network()将参数cp所指的字符串形式的网络地址转换为主机字节顺序形式的二进制ip地址,执行成功返回转换后的结果,参数无效返回-1; char *inet_ntoa(struct in_addr in); 该函数将把值为in的网络字节顺序形式的二进制IP地址转换成以"."分隔的字符串形式,执行成功返回结果字符串的指针,参数无效返回NULL; struct in_addr_inet_makeaddr(int net,int host); 该函数把网络号为参数net,主机号为host的两个地址组合成一个网络地址,如net取0xac11(172.17.0.0,主机字节顺序),host取0xf283(0.0.242.131,主机字节顺序形式),则组合后的地址172.17.242.131 .并表示为网络字节顺序形式0x83f211ac. int addr_t inet_lnaof(struct in_addr in); 该函数从参数in 中提取出主机地址,执行成功返回主机字节顺序形式的主机地址. in_addr_t inet_netof(str) 该函数从参数in中提取出网络地址,执行成功主机字节顺序形式的网络地址. 看个例子:
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> int main() { char buffer[32]; int ret=0; int host=0; int network=0; unsigned int address = 0; struct in_addr in; in.s_addr = 0; //输入一个以".分隔的字符串形式的IP地址" printf("请输入你的IP地址:"); fgets(buffer,32,stdin); buffer[31]='\0'; //示例使用inet_aton函数; if((ret=inet_aton(buffer,&in)) ==0) //int inet_aton(const char *cp,struct in_addr *inp);成功返回0值 { printf("inet_aton:\t无效的IP地址\n"); } else { printf("inet_aton:\t0x%x\n",in.s_addr); } //示例inet_addr()函数 if((address=inet_addr(buffer))==INADDR_NONE) //in_addr inet_addr(const char *cp); 成功返回转换后的结果,失败返回INADDR_NONE; { printf("inet_addr:\t无效的IP地址\n"); } else { printf("inet_addr:\t0x%x\n",address); } //示例inet_network()函数 if((address=inet_network(buffer))==-1) //in_addr inet_network(const char *cp);成功返回转换的结果,失败返回 -1; { printf("inet_network:\t无效的IP地址\n"); } else { printf("inet_network:\t0x%x\n",address); } //示例inet_ntoa()函数 if(inet_ntoa(in)==NULL) //char *inet_ntoa(struct in_addr in);成功返回结果字符串的指针,失败返回NULL; { printf("inet_ntoa:\t无效的IP地址\n"); } else { printf("inet_ntoa:\t%s\n",inet_ntoa(in)); } //示例使用inet_lnaof()与inet_netof()函数 host=inet_lnaof(in);//in_addr inet_lnaof(struct in_addr in)转换为主机字节顺序的主机地址 network=inet_netof(in); //in_addr inet_netof(struct in_adr in)转换为主机顺序的网络地址 printf("inet_lnaof:\t0x%x\n",host); printf("inet_netof:\t0x%x\n",network); in=inet_makeaddr(network,host);// struct in_addr inet_makeaddr(int net,int host);返回结构体; printf(" inet_makeaddr:0x%x\n",in.s_addr); return 0; }
结果:
请输入你的IP地址:192.168.3.4 inet_aton: 0x403a8c0 inet_addr: 0x403a8c0 inet_network: 0xc0a80304 inet_ntoa: 192.168.3.4 inet_lnaof: 0x4 inet_netof: 0xc0a803 inet_makeaddr:0x403a8c0
再此运行255.255.255.255
yang@liu:~/syc/第11章$ ./a.out 请输入你的IP地址:255.255.255.255 inet_aton: 0xffffffff inet_addr: 无效的IP地址 inet_network: 无效的IP地址 inet_ntoa: 255.255.255.255 inet_lnaof: 0xff inet_netof: 0xffffff inet_makeaddr:0xffffffff
可以看出inet_addr() 和函数inet_network()函数会把255.255.255.255当做无效的地址;