美文网首页
网络字节序和主机字节序

网络字节序和主机字节序

作者: ai___believe | 来源:发表于2017-07-18 16:56 被阅读88次

    转载 http://blog.csdn.net/msdnwolaile/article/details/50727653
    http://blog.csdn.net/lianghe_work/article/details/45170285

    我们都知道,如今的通讯方式已经趋向与多样化,异构通信(计算机软件(操作系统) + 计算机硬件(内核架构,ARM,x86)不同)也已经很普遍了,如,手机和电脑中的qq进行通信,,,

    同时,在计算机设计之初,对内存中数据的处理也有不同的方式,(低位数据存储在低位地址处或者高位数据存储在低位地址处),然而,在通信的过程中(ISO/OSI模型和TCP/IP四层模型中),数据被一步步封装(然后加入信息首部),当传到目的段时,被一步步解封,然后获取数据

    从上面我们可以看出,数据在传输的过程中,一定有一个标准化的过程,也就是说:从主机a到主机b进行通信,
    a的固有数据存储-------标准化--------转化成b的固有格式

    如上而言:a或者b的固有数据存储格式就是自己的主机字节序,上面的标准化就是网络字节序(也就是大端字节序)

    a的主机字节序----------网络字节序 ---------b的主机字节序

    主机字节序:
    就是自己的主机内部,内存中数据的处理方式,可以分为两种:
    大端字节序(big-endian):按照内存的增长方向,高位数据存储于低位内存中
    小端字节序(little-endian):按照内存的增长方向,高位数据存储于高位内存中


    网络上的数据流是字节流,对于一个多字节数值,在进行网络传输的时候,先传递哪个字节?也就是说,当接收端收到第一个字节的时候,它是将这个字节作为高位还是低位来处理呢?

    网络字节序定义:收到的第一个字节被当作高位看待,这就要求发送端发送的第一个字节应当是高位。而在发送端发送数据时,发送的第一个字节是该数字在内存中起始地址对应的字节。可见多字节数值在发送前,在内存中数值应该以大端法存放。

    所以,网络协议指定了通讯字节序:大端。只有在多字节数据处理时才需要考虑字节序,运行在同一台计算机上的进程相互通信时,一般不用考虑字节序,异构计算机之间通讯,需要转换自己的字节序为网络字节

    但是,如何知道我们的主机是那一种的呢???这个我们可以通过程序来进行验证:

    #include <stdio.h>  
    #include <arpa/inet.h>   
    int main(){  
         unsigned long a = 0x12345678;  
         unsigned char *p = (unsigned char *)(&a);  
         printf("主机字节序:%0x    %0x   %0x   %0x\n",  p[0], p[1], p[2], p[3]);  
         unsigned long b = htonl(a);  //将主机字节序转化成了网络字节序        
         p = (unsigned char *)(&b);  
         printf("网络字节序:%0x    %0x   %0x   %0x\n",  p[0], p[1], p[2], p[3]);  //16进制输出
         return 0;  
    }  
    
    运行结果:

    可以看到我的当前主机是:小端字节序

    #include <arpa/inet.h>  
      
    uint32_t htonl(uint32_t hostlong);  
      
    uint16_t htons(uint16_t hostshort);  
      
     uint32_t ntohl(uint32_t netlong);  
      
    uint16_t ntohs(uint16_t netshort);
    

    h是主机host,n是网络net,l是长整形long,s是短整形short,所以上面这些函数还是很好理解的

    #include <stdio.h>  
    #include <arpa/inet.h>  
      
    int main()  
    {  
            struct in_addr ipaddr;  
            unsigned long addr = inet_addr("192.168.1.100");  
            printf("addr = %u\n", ntohl(addr));  
      
            ipaddr.s_addr = addr;  
            printf("%s\n", inet_ntoa(ipaddr));        
            return 0;         
    } 
    

    运行结果:



    值得注意的是:

    in_addr_in inet_addr(const char *strptr);

    inet_addr的参数是一个:点分十进制字符串,返回的值为一个32位的二进制网络字节序的IPv4地址,不然的话就是:INADDR_NONE
    而返回值为:in_addr_t:IPv4,一般为uint32_t
    所以也可以定义为:unsigned long

    char * inet_ntoa(struct in_addr inaddr);

    参数是一个结构体,所以要调用必须先定义一个结构体。
    将网络地址转换成"."点隔的字符串格式。

    以下接口所需头文件:#include <arpa/inet.h>

    uint32_t htonl(uint32_t hostint32);

    功能:
    将 32 位主机字节序数据转换成网络字节序数据

    参数:
    hostint32:需要转换的 32 位主机字节序数据,uint32_t 为 32 为无符号整型

    返回值:
    成功:返回网络字节序的值

    uint16_t htons(uint16_t hostint16);

    功能:
    将 16 位主机字节序数据转换成网络字节序数据

    参数:
    hostint16:需要转换的 16 位主机字节序数据,uint16_t,unsigned short int

    返回值:
    成功:返回网络字节序的值

    测试示例:

    #include <stdio.h>  
    #include <arpa/inet.h>  
      
    int main(int argc, charchar *argv[])  
    {  
        int a = 0x01020304;  
        short int b = 0x0102;  
          
        printf("htonl(0x%08x) = 0x%08x\n", a, htonl(a));  
        printf("htons(0x%04x) = 0x%04x\n", b, htons(b));  
          
        return 0;  
    }  
    

    运行结果如下:

    uint32_t ntohl(uint32_t netint32);

    功能:
    将 32 位网络字节序数据转换成主机字节序数据

    参数:
    netint32:待转换的 32 位网络字节序数据,uint32_t,unsigned int

    返回值:
    成功:返回主机字节序的值

    uint16_t ntohs(uint16_t netint16);

    功能:
    将 16 位网络字节序数据转换成主机字节序数据

    参数:
    netint16:待转换的 16 位网络字节序数据,uint16_t,unsigned short int

    返回值:
    成功:返回主机字节序的

    三、地址转换函数以下接口所需头文件:#include <arpa/inet.h>

    int inet_pton(int family, const char *strptr, void *addrptr);

    功能:
    将点分十进制数串转换成 32 位无符号整数

    参数:
    family:协议族( AF_INET、AF_INET6、PF_PACKET 等 ),常用 AF_INET
    strptr:点分十进制数串
    addrptr:32 位无符号整数的地址

    返回值:
    成功返回 1 、 失败返回其它
    测试示例:

    #include <stdio.h>  
    #include <arpa/inet.h>  
    int main()  
    {  
        char ip_str[]="172.20.223.75";  
        unsigned int ip_uint = 0;  
        unsigned charchar *ip_p = NULL;  
      
        inet_pton(AF_INET,ip_str,&ip_uint);  
        printf("in_uint = %d\n",ip_uint);  
          
        ip_p = (charchar *)&ip_uint;  
        printf("in_uint = %d,%d,%d,%d\n",*ip_p,*(ip_p+1),*(ip_p+2),*(ip_p+3));  
      
        return 0;  
    }  
    

    运行结果如下:

    inet_ntop

    const char *inet_ntop( int family, 
                           const void *addrptr,   
                           char *strptr, 
                           size_t len );
    

    功能:
    将 32 位无符号整数转换成点分十进制数串

    参数:
    family:协议族( AF_INET、AF_INET6、PF_PACKET 等 ),常用 AF_INET
    addrptr:32 位无符号整数
    strptr:点分十进制数串
    len:strptr 缓存区长度

    len 的宏定义
    #define INET_ADDRSTRLEN   16  // for ipv4
    #define INET6_ADDRSTRLEN  46  // for ipv6
    

    返回值:
    成功:则返回字符串的首地址
    失败:返回 NULL

    测试示例:

    #include <stdio.h>  
    #include <arpa/inet.h>  
    int main()  
    {  
        unsigned char ip[] = {172,20,223,75};  
        char ip_str[16] = "NULL";  
      
        inet_ntop(AF_INET,(unsigned intint *)ip,ip_str,16);  
        printf("ip_str = %s\n",ip_str);  
      
        return 0;  
    }  
    

    运行结果如下:

    相关文章

      网友评论

          本文标题:网络字节序和主机字节序

          本文链接:https://www.haomeiwen.com/subject/tmyhkxtx.html