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);
}