[置顶] WinSock网络编程学习笔记(四)网络转换函数的实现

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);
}
[置顶] WinSock网络编程学习笔记(四)网络转换函数的实现_第1张图片


你可能感兴趣的:(数据结构,网络,二进制,网络编程,32位)