本文轉自: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);