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

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

 

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

 

    程序的原理见下图:

 

   

 

#include<stdio.h>
#include<stdlib.h>

union word{
    int a;
    char b;
}c;

int check(){
    c.a=1;
    return (c.b == 1)? 0:1;
}

int main(){
    if(check()){
        printf("big\n");
    }else{
        printf("Little\n");
    }
}


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

 

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

 

 

#include<stdio.h>

int main(){
    int a[]={1,2,3,4};
    int *ptr1 = (int *)(&a+1);
    int *ptr2 = (int *)((int)a+1);
    printf("%x , %x\n",ptr1[-1],*ptr2);
}


 

     结果是:2 , 2000000 。

 

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

     第二个值的计算如下图:

 

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

 

 

二、字节序的处理。

    

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

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

         转换所用的函数为:

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

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

 

三、地址格式的转换

 

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

     对于IPV4有以下4个函数:

          

#include<stdio.h>
#include<stdlib.h>
#include<netinet/in.h>

int main(){
    //ip地址字符串
    char* sa="202.30.45.11";
    //记录ip地址的结构体
    struct in_addr addr,ret;
    //是网络地址类型
    in_addr_t at;
    //将点分十进制字符串转换为32位网络字节序的IP
    at=inet_addr(sa);
    //十六进制输出
    printf("inet_addr:0x%x \n",at);
    //将点分十进制字符串转换为32位主机字节序,与网络字节序应该是反过来的
    printf("inet_network:0x%x \n",inet_network(sa));
    //结构体中记录IP地址的数据成员 
    addr.s_addr=at;
    //网络字节序转换为点分十进制数
    printf("inet_ntoa:%s \n",inet_ntoa(addr));
    //点分十进制数转换为网络字节序,参数为结构体
    inet_aton(sa,&ret);
    printf("inet_aton:0x%x \n",ret.s_addr);
}

       编译运行的结果:

[fsy@localhost 400]$ ./addr
inet_addr:0xb2d26ca 
inet_network:0xca262d0b 
inet_ntoa:202.30.45.11 
inet_aton:0xb2d26ca 
[fsy@localhost 400]$ 


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

 

#include<stdio.h>
#include<stdlib.h>
#include<netinet/in.h>
#include<arpa/inet.h>

int main(){
    struct in_addr ret;
    //IPV6的ip结构体
    struct in6_addr ret6;
    //存储转换的IP地址
    char buf[32];
    //IPV4
    char* sa="202.128.47.168";
    //IPV6
    char* sa6="fe80::20c:29ff:fe5f:8760";
    //点分十进制转为网络字节序,第一个参数表示IPV4
    inet_pton(AF_INET,sa,&ret);
    printf("pton: 0x%x\n",ret.s_addr);
    //网络字节序转为点分十进制,第二个参数为要转换的值,第三个参数为转换后存储的位置,第四个参数为字符串的最大长度
    inet_ntop(AF_INET,&ret,buf,32);
    printf("ntop: %s\n",buf);
    //IPV6的用法一样只是第一个参数改为AF_INET6
    inet_pton(AF_INET6,sa6,&ret6);
    printf("pton: 0x%x\n",ret6.s6_addr);
    inet_ntop(AF_INET6,&ret6,buf,32);
    printf("ntop: %s\n",buf);

}



 

四、域名与IP信息的解析

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

         可以通过返回主机信息:

#include<stdio.h>
#include<stdlib.h>
#include<netinet/in.h>
#include<netdb.h>
int main(int argc,char **argv){
    char *ptr,**pptr;
    struct hostent *hptr;
    char addr[32];

    if(argc>1){
        //将信息存入结构体中
        if((hptr=gethostbyname(argv[1]))== NULL){
            printf("gethostbyname error!:%s\n",argv[1]);
            exit(1);
        }
        //输出主机名
        printf("h_name: %s\n",hptr->h_name);
        //主机备选名称,以NULL结尾的列表
        for(pptr=hptr->h_aliases;*pptr!=NULL;pptr++){
            printf("alias: %s\n",*pptr);
        }
        //主机网络地址,以NULL结尾的列表
        for(pptr=hptr->h_addr_list;*pptr!=NULL;pptr++){
            inet_ntop(hptr->h_addrtype,*pptr,addr,sizeof(addr));
            printf("addr :%s \n",addr);
        }

    }

}

编译输出为:

[fsy@localhost 400]$ ./gethost www.baidu.com
h_name: www.a.shifen.com
alias: www.baidu.com
addr :119.75.217.56 
addr :119.75.218.45 
[fsy@localhost 400]$ 



 

    

     本篇博客出自  阿修罗道,转载请注明出处:http://blog.csdn.net/fansongy/article/details/6894960

 

 

 

GitHub 加速计划 / li / linux-dash
10.39 K
1.2 K
下载
A beautiful web dashboard for Linux
最近提交(Master分支:2 个月前 )
186a802e added ecosystem file for PM2 4 年前
5def40a3 Add host customization support for the NodeJS version 4 年前
Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐