• 网络字节序和主机字节序转换 “可交换操作”


    #include <arpa/inet.h>
    #include <stdbool.h>
    #include <stdio.h>
    
    inline bool is_little_endian(void)
    {
        int a = 1;
        return *(int *)&a == a;
    }
    
    // hton 和 ntoh 函数的代码完全相同
    
    uint32_t my_htonl(uint32_t hl)
    {
        if(is_little_endian())
        {
            return  *((unsigned char *)&hl  ) << 24  |  
                    *((unsigned char *)&hl+1) << 16  |
                    *((unsigned char *)&hl+2) << 8   |
                    *((unsigned char *)&hl+3);
        }
    	else
    	{
    		return hl;
    	}
    }
    
    uint32_t my_ntohl(uint32_t nl) // 很显然 my_htonl <=> my_ntohl
    {
    	if(is_little_endian())
    	{
    		return  *((unsigned char *)&nl  ) << 24  |
    				*((unsigned char *)&nl+1) << 16	 |
    				*((unsigned char *)&nl+2) << 8	 |
    				*((unsigned char *)&nl+3);  	 
    	}
    	else
    	{
    		return nl;
    	}
    }
    
    int main(void)
    {
        uint32_t hl = 0x12345678;
        printf("%x\n", htonl(hl));
    	printf("%x\n", ntohl(hl));
        printf("%x\n", my_htonl(hl));
    	printf("%x\n", my_ntohl(hl));
    puts("--------------------");
        
    	printf("%x\n", ntohl(123456789));
    	printf("%x\n", htonl(123456789));
    	printf("%x\n", my_ntohl(123456789));
    	printf("%x\n", my_htonl(123456789));
    
    
    
        return 0;
    }
    

      ntohl() 是可交换操作,所以 htonl()  <-> ntohl();

    这也很好理解 :

    {1 2 3 4}  <--A--> {4 3 2 1} 

    {4 3 2 1}  <--B--> {1 2 3 4} 

    把数据看做一个抽象的点,可以看出A的操作 和  B的操作 是完全相同的

    uint32_t htonl(uint32_t hostlong);
    uint16_t htons(uint16_t hostshort);
    uint32_t ntohl(uint32_t netlong);
    uint16_t ntohs(uint16_t netshort);
    
    // 其实是两个函数:
    
    uint32_t htonl(uint32_t hostlong);
    uint16_t htons(uint16_t hostshort);
    

     背景知识:

    TCP/IP协议规定,网络数据流应采用大端字节序,即低地址高字节。例如上一节的UDP段格式,地址0-1是16位的源端口号,如果这个端口号是1000(0x3e8),则地址0是0x03,地址1是0xe8,也就是先发0x03,再发0xe8,这16位在发送主机的缓冲区中也应该是低地址存0x03,高地址存0xe8。

    设 线性地址 布满 数轴的正半轴:

    设数轴上的某段地址对于的数据为:... |0x12, 0x34, 0x56, 0x78 | 0x90, 0xAB|---->(网络中的数据流)

    若把“0x12, 0x34, 0x56, 0x78 ” 这段数据看做一个int型数,它表示的数为0x12345678;  0x12所在地址为该int型数据的地址;  

         “0x90, 0xAB”                   这段看做一个short型数据,它表示的数为0x90AB;         0x90所在地址为该short型数据的地址;

    大端平台下存储 同网络中数据流的顺序... | 0x12, 0x34, 0x56, 0x78 | 0x90, 0xAB |---->

    则在小端平台下存储为:                  ... | 0x78, 0x56, 0x34, 0x12 | 0xAB, 0x90 | ---->

    0x78所在地址为 该int型数0x12345678 数据的地址

    0xAB所在地址为该short型数据0x90AB 数据的地址

    结论:

    小端存储中,多字节数据 沿着线性地址增长的方向,从最低位 开始存放

    大端存储中,多字节数据 沿着线性地址增长的方向,从最高位 开始存放 ;(这也许是小端,大端名字的由来)

  • 相关阅读:
    Linux进入单用户模式(passwd root修改密码)
    stark组件的分页,模糊查询,批量删除
    stark组件的增删改(新)
    stark组件的增删改
    stark组件之展示数据(查)
    stark组件配置,二层URL
    单例模式及设计url分发
    Django之modelform
    rbac组件权限按钮,菜单,可拔插
    rbac权限+中间件
  • 原文地址:https://www.cnblogs.com/mathzzz/p/2669816.html
Copyright © 2020-2023  润新知