Linux网络编程中的地址问题

Linux网络编程中的地址问题

在网络系统内核中 IP地址是32位,由4组十进制数组成,每组数值的范围为0~255,而平时我们使用的IP地址是16位字符串形式的IP地址,例如:“192.168.1.11”。在程序设计中经常要用到字符串表达方式的IP地址和二进制的IP地址之间的转换。

面对网络编程中众多的地址函数,你hold住了么,tiger哥没hold住,所以就写了此篇文章,希望大家能hold住网络编程。

前言:结构体struct in_addr

结构struct in_addr 在文件<netinet/in.h>中定义,结构in_addr 有一个unsigned long int 类型的成员变量s_addr。通常所说的IP地址的二进制形式就保存在成员变量s_addr中。

结构struct in_addr的原型如下:

structin_addr{

unsignedlong int s_addr;/*IP地址*/

}

一.字符串IP地址转换为二进制形式的IP地址函数

1.inet系列函数的原型:

#include<sys/socket.h>

#include<netinet/in.h>

#include<apra/inet.h>

int inet_aton(const char *cp,struct in_addr *inp);

int addr_t inet_addr(const char *cp);

int addr_t inet_network(const char *cp);

char * inet_ntoa(struct in_addr in);

struct in_addr inet_makeaddr(int net,int host);

in_addr_t inet_lnaof(struct in_addr in);

in_addr_t inet_netof(struct in_addr in);

2.inet_aton()函数

int inet_aton(const char*cp,struct in_addr *inp)

1>函数作用:inet_ation()函数将在cp中存储的点分十进制字符串类型的IP地址,转换为二进制的IP地址,转换后的值保存在指针inp指向的结构struct in_addr中。

2>形参

Ø constchar *cp:指向字符类型的IP地址。例如“192.168.1.11”

Ø struct in_addr *inp:指向二进制的网络字节顺序的IP地址

structin_addr{

unsignedlong s_addr

}

3>函数执行成功则返回非0值,参数无效则返回0。

4>实例:

#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];

structin_addr in;

in.s_addr =0;

/*输入一个字符串形式的IP地址*/

printf(“pleaseinput the ip addrss\n”);

scanf(“%s”,buffer);

buffer[31]=’\0’;

printf(“original IP地址:%s\n”,buffer);

if( 0 == inet_aton(buffer,&in)){

perror(“inet_aton”);

exit(1);

}else {

printf(“after transfer:0x%0x\n”,in.s_addr);

}

}

5> inet_aton函数最后计算出来的是网络字节序的二进制IP

3.inet_addr()函数

in_addr_tinet_addr(const char *cp)

1>函数作用:

它将参数cp所指向的字符串形式的IP地址(“192.168.1.11”)转换为二进制的网络字节序的IP地址形式

该函数的缺点是:如果IP地址是255.255.255.255。那么调用inet_addr()函数后将返回-1(因为-1的补码形式是0xFFFFFFFF)。所以不建议使用inet_addr()函数,而是使用inet_aton()函数。

2>函数形参:

const char*cp:cp指向字符串形式的IP地址。

3>函数返回值:

函数成功后返回二进制的网络字节序的IP地址(struct in_add),否则返回-1.

4>inet_addr计算出来的是网络字节序的二进制IP

5>函数实例:

#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];

structin_addr in;

in.s_addr =0;

/*输入一个字符串形式的IP地址*/

printf(“pleaseinput the ip addrss\n”);

scanf(“%s”,buffer);

buffer[31]=’\0’;

printf(“original IPaddress:%s\n”,buffer);

if((in.s_addr = inet_addr(buffer))==INADDR_NONE){

perror(“inet_addr”);

exit(1);

}else {

printf(“after transfer:0x%0x\n”,in.s_addr);

}

}

4.inet_network

in_addr_t inet_network(constchar *cp)

1>函数作用:将参数cp指向的字符串形式的网络地址转换为主机字节顺序形式的二进制IP地址。

2>函数形参

Ø const char *cp: cp指向字符串形式的IP地址。

3>函数返回值:执行成功后返回转换后的结果,参数无效后返回-1.

4>inet_network返回的是主机字节序

5>函数实例:

#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];

structin_addr in;

in.s_addr =0;

/*输入一个字符串形式的IP地址*/

printf(“pleaseinput the ip addrss\n”);

scanf(“%s”,buffer);

buffer[31]=’\0’;

printf(“original IPaddress:%s\n”,buffer);

if((in.s_addr = inet_addr(buffer))==INADDR_NONE){

perror(“inet_addr”);

exit(1);

}else {

printf(“after transfer:0x%0x\n”,in.s_addr);

}

}

总结:

1.inet_addr和inet_network函数都是用于将字符串形式转换为整数形式用的;

2.inet_addr返回的整数形式是网络字节序,而inet_network返回的整数形式是主机字节序.

3.inet_addr 和inet_network有一个小缺陷,那就是当IP是255.255.255.255时,这两个函数会认为这是个无效的IP地址,这是历史遗留问题,其实在目前大部分的路由器上,这个 255.255.255.255的IP都是有效的。

4.inet_aton认为255.255.255.255是有效的,所以建议使用inet_aton。并且inet_aton函数返回的是网络字节序的IP地址。

二.进制IP地址转换为字符串形式的IP地址

1.char * inet_ntoa(struct in_addr in);

1>函数作用:将数值为in的网络字节序形式的二进制IP地址转换为字符串形式的IP地址。

2>形参:struct in_addr in:指向二进制的IP地址

3>函数返回值:执行成功返回结果字符串的指针,参数无效返回NULL.

4>函数实例:

#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];

char *str;

structin_addr in;

in.s_addr =0;

/*输入一个字符串形式的IP地址*/

printf(“pleaseinput the ip addrss\n”);

scanf(“%s”,buffer);

buffer[31]=’\0’;

printf(“original IP地址:%s\n”,buffer);

if( 0 == inet_aton(buffer,&in)){

perror(“inet_aton”);

exit(1);

}else {

printf(“the first transfer:0x%0x\n”,in.s_addr);

}

printf(“begin two process:\n”);

if( (str =inet_ntoa(in) == NULL ){

printf(“inet_ntoa:argumentinvalid\n”);

} else {

printf(“thesecond transfer:%s\n”,str);

}

}

说明:

1.函数inet_ntoa()的返回值为一个指向字符串的指针,该内存函数inet_ntoa()每次调用都会重新覆盖,因此函数不安全,可能存在某种隐患

2.实例:

#include<stdio.h>

#include<string.h>

#include<stdlib.h>

#include<sys/socket.h>

#include<netinet/in.h>

#include<arpa/inet.h>

int main()

{

structin_addr ip1,ip2;

char *str1 ;

char *str2;

ip1.s_addr = 192<<24| 168 <<16 |1 <<8 | 1;

ip2.s_addr =255<<24 | 255 <<16 |255<<8|255;

str1 = inet_ntoa(ip1);

str2 = inet_ntoa(ip2);

printf(“ip1:0x%xà%s\n”,ip1.s_addr,str1);

printf(“ip2:0x%xà%s\n”,ip2.s_addr,str2);

}

输出结果为:

ip1: 0xc0a80101à255.255.255.255;

ip2:0xffffffffà255.255.255.255;

表明函数inet_ntoa在进行二进制IP地址到字符串IP地址的转换过程中是不可重入的,这个函数转换两个不同的IP地址得到了同一个结果。此类函数在调用之后,需要立即将结果取出,没有取出结果之前不能进行同样函数的调用。

三.最新的地址转换函数inet_pton()和inet_ntop()函数

inet_pton和inet_ntop这2个函数能够处理ipv4和ipv6。算是比较新的函数了。inet_pton函数原型如下[将“点分十进制” -> “整数”],并且这两个函数是一套安全的协议无关的地址转换函数。所谓安全即这两个函数是可重入的,并且这些函数支持多种地址类型,包括IPv4和IPv6.

1.inet_pton()函数

1>函数功能

inet_pton()函数将字符串类型的IP地址转换为二进制类型。

2>函数原型

#include<sys/types.h>

#include<sys/socket.h>

#include<arpa/inet.h>

intinet_pton(int af, const char *src, void *dst);

3>函数形参:

Ø intaf:af表示网络类型的协议族,在IPv4下的值为AF_INET;

Ø src:存放需要转换的字符串

Ø dst :存放转换后的结果,在IPv4下,dst指向结构struct in_addr的指针。

4>函数返回值

当函数inet_pton()的返回值为-1的时候,通常是用于af所指定的协议族不支持造成,此时errno的返回值为EAFNOSUPPORT;当函数的返回值为0时,表示src指向的值不是合法的IP地址;当函数的返回值为正值时,表示转换成功。

2.inet_ntop()函数

1>函数功能

inet_pton()函数将二进制的网络IP地址转换为字符串。

2>函数原型:

#include<sys/types.h>

#include<sys/socket.h>

#include<arpa/inet.h>

intinet_nton(int af, const void *src, char *dst,socklen_t cnt);

3>函数形参:

Ø intaf:af表示网络类型的协议族,在IPv4下的值为AF_INET;

Ø src :为需要转换的二进制IP地址,在IPv4下,src指向一个structin_addr结构类型的指针。

Ø dst指向保存结果缓冲区的指针

Ø cnt的值是dst缓冲区的大小

4>函数返回值

Inet_ntop()函数返回一个指向dst的指针。当发生错误时,返回NULL。当af设定的协议族不支持时,errno设置为EAFNOSUPPORT;当dst缓冲区大小过小的时候errno的值为ENOSPC。

3.函数实例:

#include<stdio.h>

#include<string.h>

#include<stdlib.h>

#include<sys/socket.h>

#include<sys/types.h>

#include<arpa/inet.h>

intmain(int argc,char *argv[])

{

structin_addr ip;

charipstr[] = “192.168.1.1”;

charaddr[ADDRLEN];

constchar * str = NULL;

interr = 0;

if(err > 0){

printf(“inet_pton:ip %s value is :0x%x\n”,ipstr,ip.s_addr);

}

//把192.168.12.255转换为网络字节序

ip.s_addr = htonl(192 << 24 | 168<<16 | 12<<8 | 255);

str = (const char *)inet_ntop(AF_INET,(void*)&ip,(char *)&addr[0],ADDRLEN);

if(str){

printf(“inet_ntop :ip 0x%x is%s\n”,ip.s_addr,str);

}

}

四.inet_makeaddr()函数,inet_lnaof()函数和inet_netof()函数

1.struct in_addr inet_makeaddr(int net,int host)

1>函数功能:一个主机的IP地址分为网络地址和主机地址,inet_makeaddr()函数将主机字节序的网络地址net和主机地址host合并成一个网络字节序的IP地址。

2>函数形参:

Ø intnet:存放网络号参数(二进制形式的主机字节序)

Ø inthost:存放主机号地址(二进制形式的主机字节序)

3>函数返回值:

返回一个网络字节序的IP地址

4>函数实例:

unsigned long net,host;

net = 0x0000007F;

host = 0x00000001;

struct in_addr ip = inet_makeaddr(net,hst);

2.in_addr_t inet_lnaof(struct in_addr in)

1>函数功能:

该函数从参数in中提取出主机地址,执行成功后返回主机字节顺序形式的主机地址。

例如:172.17.242.131属于B类地址,则主机号为低16位,主机地址为0.0.242.131,按主机字节顺序输出则为0xf283。

2>函数形参

Ø struct in_addr in:in存放的是主机字节序的二进制形式的IP地址

3>函数返回值:

返回主机字节序的二进制形式的IP主机部分的数值

4>函数实例:

const char *addr = “127.0.0.1”;

unsignedlong ip = inet_network(addr);

unsignedlong host_id = inet_lnaof(ip);

3.in_addr_t inet_netof(struct in_addr in)

1>函数功能:

该函数从参数in中提取出网络地址,执行成功后返回主机字节顺序形式的网络地址。

如:172.17.242.131属于B类地址,则高16位表示网络号,网络地址为172.17.0.0。

2>函数形参

Ø struct in_addr in:in存放的是主机字节序的二进制形式的IP地址

3>函数返回值:

返回主机字节序的二进制形式的IP网络部分的数值

4>函数实例:

const char *addr = “127.0.0.1”;

unsigned long ip = inet_network(addr);

unsigned long network_id = inet_netof(ip);




你可能感兴趣的:(linux)