Linux網絡編程中的地址問題

本文轉自:http://blog.csdn.net/tigerjibo/article/details/6787986,感謝作者!

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{

        unsigned long  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>形參

Ø  const char *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_t inet_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>函數形參:

Ø  int af: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>函數形參:

Ø  int af: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>

int main(int argc,char *argv[])

{

   struct in_addr ip;

   char  ipstr[] = “192.168.1.1”;

   char  addr[ADDRLEN];

   const char * str = NULL;

   int err = 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>函數形參:

Ø  int net:存放網絡號參數(二進制形式的主機字節序)

Ø  int host:存放主機號地址(二進制形式的主機字節序)

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”;

unsigned long  ip = inet_network(addr);

unsigned long  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);


發佈了17 篇原創文章 · 獲贊 8 · 訪問量 7萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章