• IP地址转换、主机大小端、htonl、ntohl实现


    http://blog.csdn.net/zww0815/article/details/7592940

    1. #include <IOSTREAM>   
    2. //#include <WINSOCK.H>   
    3. using namespace std;  
    4.   
    5. typedef unsigned short int uint16;  
    6. typedef unsigned long int uint32;  
    7.   
    8. // 短整型大小端互换   
    9. #define BigLittleSwap16(A)  ((((uint16)(A) & 0xff00) >> 8) | \   
    10. (((uint16)(A) & 0x00ff) << 8))  
    11. // 长整型大小端互换   
    12.   
    13. #define BigLittleSwap32(A)  ((((uint32)(A) & 0xff000000) >> 24) | \   
    14.     (((uint32)(A) & 0x00ff0000) >> 8) | \  
    15.     (((uint32)(A) & 0x0000ff00) << 8) | \  
    16. (((uint32)(A) & 0x000000ff) << 24))  
    17.   
    18. // 本机大端返回1,小端返回0   
    19. int checkCPUendian()  
    20. {  
    21.     union{  
    22.         unsigned long int i;  
    23.         unsigned char s[4];  
    24.     }c;  
    25.       
    26.     c.i = 0x12345678;  
    27.     return (0x12 == c.s[0]);  
    28. }  
    29.   
    30. // 模拟htonl函数,本机字节序转网络字节序   
    31. unsigned long int t_htonl(unsigned long int h)  
    32. {  
    33.     // 若本机为大端,与网络字节序同,直接返回   
    34.     // 若本机为小端,转换成大端再返回   
    35.     return checkCPUendian() ? h : BigLittleSwap32(h);  
    36. }  
    37.   
    38. // 模拟ntohl函数,网络字节序转本机字节序   
    39. unsigned long int t_ntohl(unsigned long int n)  
    40. {  
    41.     // 若本机为大端,与网络字节序同,直接返回   
    42.     // 若本机为小端,网络数据转换成小端再返回   
    43.     return checkCPUendian() ? n : BigLittleSwap32(n);  
    44. }  
    45.   
    46. // 模拟htons函数,本机字节序转网络字节序   
    47. unsigned short int t_htons(unsigned short int h)  
    48. {  
    49.     // 若本机为大端,与网络字节序同,直接返回   
    50.     // 若本机为小端,转换成大端再返回   
    51.     return checkCPUendian() ? h : BigLittleSwap16(h);  
    52. }  
    53.   
    54. // 模拟ntohs函数,网络字节序转本机字节序   
    55. unsigned short int t_ntohs(unsigned short int n)  
    56. {  
    57.     // 若本机为大端,与网络字节序同,直接返回   
    58.     // 若本机为小端,网络数据转换成小端再返回   
    59.     return checkCPUendian() ? n : BigLittleSwap16(n);  
    60. }  
    61.   
    62. //8个二进制(2个十六进制)数转换成十进制数,不含a-f。即00-99的转换      
    63. int transfer_0(int x)    
    64. {    
    65.     int y;//结果      
    66.     int temp;//临时值      
    67.       
    68.     y=x%10;//个位数      
    69.     temp=(x%100-y)/10;//十位数      
    70.     y+=temp*16;    
    71.     return y;    
    72. }    
    73.   
    74. //32个二进制(4个十六进制)数转换成十进制数,不含a-f。即0000-9999的转换      
    75. void transfer_1(unsigned int x)    
    76. {    
    77.     //从右向左      
    78.     int temp1=x%100;    
    79.     int y1=transfer_0(temp1);    
    80.       
    81.     int temp2=(x%10000-temp1)/100;    
    82.     int y2=transfer_0(temp2);    
    83.       
    84.     int temp3=(x%1000000-temp1-temp2*100)/10000;    
    85.     int y3=transfer_0(temp3);    
    86.       
    87.     int temp4=(x%100000000-temp1-temp2*100-temp3*10000)/1000000;    
    88.     int y4=transfer_0(temp4);    
    89.       
    90.     printf("结果是:%d.%d.%d.%d\n",y4,y3,y2,y1);    
    91. }  
    92.   
    93. //将16进制数数转化成10进制数,一位的0-F。      
    94. int transfer_0(char x)    
    95. {    
    96.     int y=0;//返回值      
    97.     if (x>='0' && x<='9')//0-9的数字      
    98.     {    
    99.         y=x-'0';    
    100.         return y;    
    101.     }    
    102.     if (x>='a' && x<='f')//a-f的字母      
    103.     {    
    104.         y=x-'a'+10;    
    105.         return y;    
    106.     }    
    107.     if (x>='A' && x<='F')//A-F的字母      
    108.     {    
    109.         y=x-'A'+10;    
    110.         return y;    
    111.     }    
    112.     printf("参数错误!");    
    113.     exit(1);    
    114. }  
    115.   
    116.   
    117. //将16进制数数转化成10进制数,八位的00000000-FFFFFFFF。      
    118. void transfer_3(char x[],int n)//长度为8      
    119. {    
    120.     //从左往右      
    121.     int y0=transfer_0(x[0]);    
    122.     int y1=transfer_0(x[1]);    
    123.     int y2=transfer_0(x[2]);    
    124.     int y3=transfer_0(x[3]);    
    125.     int y4=transfer_0(x[4]);    
    126.     int y5=transfer_0(x[5]);    
    127.     int y6=transfer_0(x[6]);    
    128.     int y7=transfer_0(x[7]);    
    129.       
    130.     printf("结果是:%d.%d.%d.%d\n",y0*16+y1,y2*16+y3,y4*16+y5,y6*16+y7);        
    131. }  
    132.   
    133.   
    134. //将16进制数数转化成10进制数,八位的00000000-FFFFFFFF。      
    135. void transfer_4(char x[])    
    136. {    
    137.     //从左往右      
    138.     int y1=transfer_0(x[0])*16+transfer_0(x[1]);    
    139.     int y2=transfer_0(x[2])*16+transfer_0(x[3]);    
    140.     int y3=transfer_0(x[4])*16+transfer_0(x[5]);    
    141.     int y4=transfer_0(x[6])*16+transfer_0(x[7]);    
    142.       
    143.     printf("结果是:%d.%d.%d.%d\n",y1,y2,y3,y4);        
    144. }    
    145.   
    146.   
    147. int main()  
    148. {  
    149.     int ret;  
    150.     ret = checkCPUendian();  
    151.   
    152.     if (ret == 1)  
    153.     {  
    154.         printf("返回1,本机为大端\n");  
    155.     }  
    156.     else  
    157.     {  
    158.         printf("返回0,本机为小端\n");  
    159.     }  
    160.       
    161.     return 0;  
    162. }  

    -------------------------------

    htonl(),htons(),ntohl(),ntons()--大小端模式转换函数

    不同机器内部对变量的字节存储顺序不同,有的采用大端模式(big-endian),有的采用小端模式(little-endian)。
    大端模式是指高字节数据存放在低地址处,低字节数据放在高地址处。
    小端模式是指低字节数据存放在低地址处,高字节数据放在高地址处。

    在网络上传输数据时,由于数据传输的两端可能对应不同的硬件平台,采用的存储字节顺序也可能不一致,因此 TCP/IP 协议规定了在网络上必须采用网络字节顺序(也就是大端模式)
    通过对大小端的存储原理分析可发现,对于 char 型数据,由于其只占一个字节,所以不存在这个问题,这也是一般情况下把数据缓冲区定义成 char 类型 的原因之一。对于 IP 地址、端口号等非 char 型数据,必须在数据发送到网络上之前将其转换成大端模式,在接收到数据之后再将其转换成符合接收端主机的存储模式。

    Linux 系统为大小端模式的转换提供了 4 个函数,输入 man byteorder 命令可得函数原型:

    #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);

    htonl 表示 host to network long ,用于将主机 unsigned int 型数据转换成网络字节顺序;
    htons 表示 host to network short ,用于将主机 unsigned short 型数据转换成网络字节顺序;
    ntohl、ntohs 的功能分别与 htonl、htons 相反。

  • 相关阅读:
    客户端rsyslog配置文件详解
    logstash插件配置-codec插件说明json和multiline
    Linux流量监控工具
    单线程 Redis 为什么这么快,看看这篇就知道了
    RabbitMQ Network Partitions 处理策略
    inux 下配置网卡的别名即网卡子IP的配置 转
    Prometheus的监控解决方案(含监控kubernetes)
    Prometheus+Grafana监控Kubernetes
    python输入一维数组(输入以空格为间隔的一行)
    用gdb来理解:值传递/指针传递/引用传递
  • 原文地址:https://www.cnblogs.com/kungfupanda/p/3056505.html
Copyright © 2020-2023  润新知