网络编程基础一

一、数据存储顺序:大端和小端

         高位字节存储高字节称为小端模式,通常都计算机采用这个模式存储。而网络则采用大端传输。所以需要转换

 

      面试有时会出这么个题:写一个程序判断程序的存储是大端还是小端?

 

    程序的原理见下图:

 

    

 

[cpp]  view plain  copy
 
 
  1. #include<stdio.h>  
  2. #include<stdlib.h>  
  3.   
  4. union word{  
  5.     int a;  
  6.     char b;  
  7. }c;  
  8.   
  9. int check(){  
  10.     c.a=1;  
  11.     return (c.b == 1)? 0:1;  
  12. }  
  13.   
  14. int main(){  
  15.     if(check()){  
  16.         printf("big\n");  
  17.     }else{  
  18.         printf("Little\n");  
  19.     }  
  20. }  


         利用Union的特点,判断出了大端还是小端。

 

      还有一道经典的面试题是 :

 

 

[cpp]  view plain  copy
 
 
  1. #include<stdio.h>  
  2.   
  3. int main(){  
  4.     int a[]={1,2,3,4};  
  5.     int *ptr1 = (int *)(&a+1);  
  6.     int *ptr2 = (int *)((int)a+1);  
  7.     printf("%x , %x\n",ptr1[-1],*ptr2);  
  8. }  


 

     结果是:2 , 2000000 。

 

     第一个值的计算请参考 面试知识总结(一) 中的第四题。

     第二个值的计算如下图:

 

    将a转换为整形,然后增加1,再转回指针型,相当于只移动了一个bit。由于是小端存储,会将下一个数的末尾读进来。

 

 

二、字节序的处理。

    

         因为存在大端小端的问题,所以就要进行统一的转换。

         注意字符串是不用转换的,因为一个字符正好占一字节。存储顺序不影响值。而浮点数也不用转换,因为浮点数的读取规则是在cpu中定义的,是一致的。

         转换所用的函数为:

                htons(),htonl();        主机转为网络字节序,s为short , l为long

                ntohs(),ntohl();         网络转为主机字节序。

 

三、地址格式的转换

 

         通常情况下,都是用点分十进制(如:202.134.23.145)来表示IP地址。是个字符串。但是程序中处理时用到的是一个二进制的值。所以要进行转换。

     对于IPV4有以下4个函数:

          

[cpp]  view plain  copy
 
 
  1. #include<stdio.h>  
  2. #include<stdlib.h>  
  3. #include<netinet/in.h>  
  4.   
  5. int main(){  
  6.     //ip地址字符串  
  7.     char* sa="202.30.45.11";  
  8.     //记录ip地址的结构体  
  9.     struct in_addr addr,ret;  
  10.     //是网络地址类型  
  11.     in_addr_t at;  
  12.     //将点分十进制字符串转换为32位网络字节序的IP  
  13.     at=inet_addr(sa);  
  14.     //十六进制输出  
  15.     printf("inet_addr:0x%x \n",at);  
  16.     //将点分十进制字符串转换为32位主机字节序,与网络字节序应该是反过来的  
  17.     printf("inet_network:0x%x \n",inet_network(sa));  
  18.     //结构体中记录IP地址的数据成员   
  19.     addr.s_addr=at;  
  20.     //网络字节序转换为点分十进制数  
  21.     printf("inet_ntoa:%s \n",inet_ntoa(addr));  
  22.     //点分十进制数转换为网络字节序,参数为结构体  
  23.     inet_aton(sa,&ret);  
  24.     printf("inet_aton:0x%x \n",ret.s_addr);  
  25. }  

       编译运行的结果:

[plain]  view plain  copy
 
 
  1. [fsy@localhost 400]$ ./addr  
  2. inet_addr:0xb2d26ca   
  3. inet_network:0xca262d0b   
  4. inet_ntoa:202.30.45.11   
  5. inet_aton:0xb2d26ca   
  6. [fsy@localhost 400]$   


      而对于结构不同的IPV6就不行了。但有两个函数可以通用于IPV4和IPV6:

 

[cpp]  view plain  copy
 
 
  1. #include<stdio.h>  
  2. #include<stdlib.h>  
  3. #include<netinet/in.h>  
  4. #include<arpa/inet.h>  
  5.   
  6. int main(){  
  7.     struct in_addr ret;  
  8.     //IPV6的ip结构体  
  9.     struct in6_addr ret6;  
  10.     //存储转换的IP地址  
  11.     char buf[32];  
  12.     //IPV4  
  13.     char* sa="202.128.47.168";  
  14.     //IPV6  
  15.     char* sa6="fe80::20c:29ff:fe5f:8760";  
  16.     //点分十进制转为网络字节序,第一个参数表示IPV4  
  17.     inet_pton(AF_INET,sa,&ret);  
  18.     printf("pton: 0x%x\n",ret.s_addr);  
  19.     //网络字节序转为点分十进制,第二个参数为要转换的值,第三个参数为转换后存储的位置,第四个参数为字符串的最大长度  
  20.     inet_ntop(AF_INET,&ret,buf,32);  
  21.     printf("ntop: %s\n",buf);  
  22.     //IPV6的用法一样只是第一个参数改为AF_INET6  
  23.     inet_pton(AF_INET6,sa6,&ret6);  
  24.     printf("pton: 0x%x\n",ret6.s6_addr);  
  25.     inet_ntop(AF_INET6,&ret6,buf,32);  
  26.     printf("ntop: %s\n",buf);  
  27.   
  28. }  



 

四、域名与IP信息的解析

         IP地址不好记,所以便有了域名。

         可以通过返回主机信息:

[cpp]  view plain  copy
 
 
  1. #include<stdio.h>  
  2. #include<stdlib.h>  
  3. #include<netinet/in.h>  
  4. #include<netdb.h>  
  5. int main(int argc,char **argv){  
  6.     char *ptr,**pptr;  
  7.     struct hostent *hptr;  
  8.     char addr[32];  
  9.   
  10.     if(argc>1){  
  11.         //将信息存入结构体中  
  12.         if((hptr=gethostbyname(argv[1]))== NULL){  
  13.             printf("gethostbyname error!:%s\n",argv[1]);  
  14.             exit(1);  
  15.         }  
  16.         //输出主机名  
  17.         printf("h_name: %s\n",hptr->h_name);  
  18.         //主机备选名称,以NULL结尾的列表  
  19.         for(pptr=hptr->h_aliases;*pptr!=NULL;pptr++){  
  20.             printf("alias: %s\n",*pptr);  
  21.         }  
  22.         //主机网络地址,以NULL结尾的列表  
  23.         for(pptr=hptr->h_addr_list;*pptr!=NULL;pptr++){  
  24.             inet_ntop(hptr->h_addrtype,*pptr,addr,sizeof(addr));  
  25.             printf("addr :%s \n",addr);  
  26.         }  
  27.   
  28.     }  
  29.   
  30. }  

编译输出为:

[plain]  view plain  copy
 
 
  1. [fsy@localhost 400]$ ./gethost www.baidu.com  
  2. h_name: www.a.shifen.com  
  3. alias: www.baidu.com  
  4. addr :119.75.217.56   
  5. addr :119.75.218.45   
  6. [fsy@localhost 400]$   
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值