WinSock提供了IP地址和点分十进制地址之间的转换函数,IP地址在网络模块中使用,点分十进制则是方便平常我们阅读而存在。
今天初步认识了下两个转换函数:
1.
函数原型:
unsigned long WSAAPI inet_addr(const char FAR*cp);
返回值:
成功返回一个32位二进制描述的网络字节序地址;如果传入的字符串不是合法地址,函数失败且返回INADDR_NONE,WinSock中定义为0xffffffff;
如“a,b,c,d”之中的任意一部分超过255都将导致错误。而当输入的地址是广播地址"255.255.255.255"时,
函数也返回错误值。因此该函数不能用于对广播地址进行转换。
2.
函数原型:
unsigned long WSAAPI inet_ntoa(struct in_addr in);
返回值:
成功返回一个指向静态缓冲区的指针。失败返回NULL。该函数用于把网络字节序的IP地址转换为点分十进制的IP地址。
下面是原书中的代码,我只是加了一些注释,方便像和我一样的同学学习,呵呵。
NetConvt.c
#include<stdio.h> #include<winsock2.h> //需要使用其中的 struct in_addr 数据结构 #define INADDR_INVALD 0xffffffff //无效地址 static unsigned long range[] = {0xffffffff,0xffffff,0xffff,0xff}; //函数 net_htons 和 net_ntohs 是 短整数 主机字节序和网络字节序之间的转换,都是左移, //只有在小尾数的机器上需要这样的实现,如果是大尾数的机器,直接返回传入的参数即可。 unsigned short net_htons(unsigned short shost) { unsigned char *p = (unsigned char *)&shost; return (unsigned short)(p[0] << 8 | p[1]); //短整型占两个字节,把高字节和低字节交换位置 } unsigned short net_ntohs(unsigned short snet) { unsigned char *p = (unsigned char *)&snet; return (unsigned short)(p[0] << 8 | p[1]); } //函数 net_htonl 和 net_ntohl 是 长整数 主机字节序和网络字节序之间的转换 unsigned long net_htonl(unsigned long lhost) { unsigned char *p = (unsigned char *)&lhost; return(unsigned long)(p[3] | (p[2] << 8) | (p[1] << 16) | (p[0] << 24));//长整数占4个字节 } unsigned long net_ntohl(unsigned long lnet) { unsigned char *p = (unsigned char *)&lnet; return(unsigned long)(p[3] | (p[2] << 8) | (p[1] << 16) | (p[0] << 24)); } //net_ntoa该函数将网络字节序的IP地址转换为点分十进制的IP地址。 char *net_ntoa(struct in_addr addr) { static char buf[16]; //转换后最大长度为15 unsigned char *p = (unsigned char*)&addr; sprintf(buf,"%d.%d.%d.%d",p[0],p[1],p[2],p[3]); return buf; } //下面这个函数是将点分十进制的IP地址转换为网络字节序的IP地址 unsigned long net_addr(const char *cp) { unsigned char addr[4],*p = addr,c = *cp;//c 为指针cp当前指向的地址中的值.. unsigned long value; int i,n,base,digit; while(1)//循环解析 { base = 10,value = 0,digit = 0; //判断头号位是10进制还是8进制或16进制数 if(!isdigit(c)) //判断传入的C是否是0~9数字 { return INADDR_INVALD; } if(c == '0') //8进制 { base = 8, /*base相当于一个标志*/ c = *++cp; //指针移动 if(c == 'x' || c == 'X') base = 16,c = *++cp; //16进制 } while( c = *cp++) { if(isdigit(c)) { if(base == 8 && c >= '8') //8进制中的数没有>=8的 return INADDR_INVALD; value = value * base + (c - '0'); } else if(base == 16 && isxdigit(c)) value = (value << 4) | (c + 10 - (islower(c) ?'a' : 'A')); else break; digit = 1; //到这说明至少有一个数字 if(c == '.')//遇到“.”的处理 { if(!digit || p >= addr + 3 || value > 0xff)//0xff = 255 return INADDR_INVALD; *p++ = (unsigned char)value;//将值保存到数组中,然后指针移动 c = *cp; } else break; } } n = p - addr; //得到元素个数 //解析完成,看是否有数字,检查尾部字节以及值的范围 if(!digit || (value > range[n]) || (c != '\0' && !isspace(c))) return INADDR_INVALD; //把地址的最后一部分保存到addr中 for(i = 3;i >= n;i--,value >>= 8) addr[i] = (unsigned char)(value & 0xff); value = *(unsigned long *)addr; return value; } //下面是测试 void main() { unsigned short host_s = 0x1234,net_s; unsigned long host_l = 0x12345678,net_l; char *addr_dec = "192.168.10.26",*p; struct in_addr addr; // char c; net_s = net_htons(host_s); net_l = net_htonl(host_l); printf("net byte order is :net_s = 0x%x,net_l = 0x%x\n",net_s,net_l); addr.s_addr = net_addr(addr_dec); p = net_ntoa(addr); printf("net addr is 0x%x,string addr is %s\n",addr.s_addr,p); // scanf("%c",&c); }