• 详解C语言的htons和htonl函数、大尾端、小尾端


    在Linux和Windows网络编程时需要用到htons和htonl函数,用来将主机字节顺序转换为网络字节顺序。

         在Intel机器下,执行以下程序

    int main()
    {
       printf("%d /n",htons(16));
          return 0;
    }

    得到的结果是4096,初一看感觉很怪。

        解释如下,数字16的16进制表示为0x0010,数字4096的16进制表示为0x1000。 由于Intel机器是小尾端,存储数字16时实际顺序为1000,存储4096时实际顺序为0010。因此在发送网络包时为了报文中数据为0010,需要经过htons进行字节转换。如果用IBM等大尾端机器,则没有这种字节顺序转换,但为了程序的可移植性,也最好用这个函数。

       另外用注意,数字所占位数小于或等于一个字节(8 bits)时,不要用htons转换。这是因为对于主机来说,大小尾端的最小单位为字节(byte)。

    什么是大端模式(big-endian),为什么使用大端模式(big-endian)。

    uint16_t htons(uint16_t hostshort);
      htons的功能:将一个无符号短整型数值转换为网络字节序,即大端模式(big-endian)
      参数u_short hostshort: 16位无符号整数
      返回值:TCP / IP网络字节顺序
      htons 是把你机器上的整数转换成“网络字节序”, 网络字节序是 big-endian,也就是整数的高位字节存放在内存的低地址处。 而我们常用的 x86 CPU (intel, AMD) 电脑是 little-endian,也就是整数的低位字节放在内存的低字节处。举个例子吧。假定你的port是0x1234,在网络字节序里 这个port放到内存中就应该显示成addr addr+1,也就是:0x12 0x34;而在x86电脑上,0x1234放到内存中实际是:addr addr+1,也就是:0x34 0x12。htons 的用处就是把实际内存中的整数存放方式调整成“网络字节序”的方式。

    第一个问题:为什么使用两个字节,也就是16位来存储。

      这个简单一些,因为一个字节只能存储8位2进制数,而计算机的端口数量是65536个,也就是2^16,两个字节。

    第二个为题:为什么计算机需要大端模式和小端模式?

      小端模式 :强制转换数据不需要调整字节内容,1、2、4字节的存储方式一样。
      大端模式 :符号位的判定固定为第一个字节,容易判断正负。

        big endian:大尾端,也称大端(高位)优先存储。
        little endian:小尾端,也称小端(低位)优先存储。
     
       如下00000000 00000000 00000000 00000001的存储
           
        大尾端: 00000000 00000000 00000000 00000001
               addr+0    addr+1     addr+2   addr+3     //先存高有效位(在低地址)
      
       小尾端: 00000001 00000000 00000000 00000000
               addr+0    addr+1     addr+2   addr+3     //先存低有效位(在低地址)
     
       故要判断机器的体系结构是大尾端还是小尾端,以下程序可以完成任务:
      
       

    #include <stdio.h>
    int main()
    {
        int tt = 1;
        char *c = (char*)(&tt);
        if(*c == 1)
        {
            printf("litte endian ");
        }
        else
        {
            printf("big endian ");
        }
        return 0;
    }

    大小尾端数据间的相互转换

    /*
          usage: to convert between the form of big-endian and little-endian
          author: ydzhang
          date: 2008年12月6日20:23:48
    */
    #include <stdio.h>
    typedef unsigned int u32;
    typedef unsigned short u16;

    #define BSWAP_16(x) 
            (u16) ( ((((u16)(x) & 0x00ff)) << 8) 
            | (((u16)(x) & 0xff00) >> 8) )

    u16 bswap_16(u16 x)
    {
        return ((x & 0x00ff) << 8) | ((x & 0xff00) >> 8);
    }

    u32 bswap_32(u32 x)
    {
        return ((x & 0x000000ff) << 24) |
               ((x & 0x0000ff00) << 8) |
               ((x & 0x00ff0000) >> 8) |
               ((x & 0xff000000) >> 24);
    }

    int main()
    {
         u16 num_16 = 0x1234;
         u32 num_32 = 0x12345678;

        printf("%x ", bswap_16(num_16));
        printf("%x ", BSWAP_16(num_16));
        printf("%x ", bswap_32(num_32));
        return 0;
    }
     

  • 相关阅读:
    Nginx 变量漫谈
    nginx 常见参数以及重定向参数配置
    Nginx proxy_pass配置
    [效果不错] nginx 高并发参数配置及linux内核参数优化,完整的内核优化设置。PHP-FPM高负载解决办法。
    网页 大文件上传解决方案(500M以上)
    VUE 大文件上传解决方案(500M以上)
    JavaScript 大文件上传解决方案(500M以上)
    JS 大文件上传解决方案(500M以上)
    C#.NET 大文件上传解决方案(500M以上)
    ASP.NET 大文件上传解决方案(500M以上)
  • 原文地址:https://www.cnblogs.com/sddai/p/5790479.html
Copyright © 2020-2023  润新知