文章目录

  • 一、网络字节序
  • 1、大端模式和小端模式
  • 2、判断大端模式和小端模式
  • 3、大端模式和小端模式相互转换
  • 二、字节序转换函数
  • 三、IP地址详解
  • 1、IP地址的概念
  • 2、IP地址的两种表示方法:整数和点分十进制
  • 3、判断IP地址是否合法
  • 四、IP地址转换
  • 1、将点分十进制数串转换成 32 位无符号整数
  • 2、将 32 位无符号整数转换成点分十进制数串


一、网络字节序

1、大端模式和小端模式

字节序是指多字节数据的存储顺序,在设计计算机系统的时候,有两种处理内存中数据的方法:大端格式、小端格式。

  • 小端格式(Little-Endian):将低位字节数据存储在低地址;
  • 大端格式(Big-Endian):将高位字节数据存储在低地址。

举个简单的例子,对于整形 0x12345678,它在大端格式和小端格式的系统中,分别如下图所示的方式存放:

网络字节序和IP地址详解_IP

2、判断大端模式和小端模式

【下面例子为确定主机的字节序】:

#include <stdio.h>  
int main(int argc, charchar *argv[])  
{  
    unsigned int a = 0x12345678;  
    unsigned char *p = (unsigned char *)&a; // 取低地址上的数据
    if(0x12 == *p){  
        printf("Big-Endian\n");  
    }else if(0x78 == *p){  
        printf("Little-Endian\n");  
    }  
    return 0;  
}

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

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

3、大端模式和小端模式相互转换

使用移位运算:

uint32_t reversebytes_uint32t(uint32_t value){
    return (value & 0x000000FFU) << 24 | (value & 0x0000FF00U) << 8 | 
        (value & 0x00FF0000U) >> 8 | (value & 0xFF000000U) >> 24; 
}
上述代码中,将低8位(0~8位)左移24位,变成了高8位(24~32位),8~16位左移8位变成了
(16~24位)。将原高8位和高16位右移,变成了新的低8位和低16位。

二、字节序转换函数

#include <arpa/inet.h>
// 将 32位主机字节序数据转换成网络字节序数据
//(h:host, n:net,l:long)
uint32_t htonl(uint32_t hostint32);
// 将 16 位主机字节序数据转换成网络字节序数据
uint16_t htons(uint16_t hostint16);
// 将 32 位网络字节序数据转换成主机字节序数据
uint32_t ntohl(uint32_t netint32);
// 将 16 位网络字节序数据转换成主机字节序数据
uint16_t ntohs(uint16_t netint16);

三、IP地址详解

1、IP地址的概念

IP地址分为网络IP和主机IP:

网络字节序和IP地址详解_字节序_02


网络字节序和IP地址详解_IP地址_03


网络字节序和IP地址详解_网络字节序_04

  • A类地址第一字节为网络ID,后三个字节为主机ID,范围是1.0.0.0到126.255.255.255; 默认子网掩码:255.0.0.0;
  • B类地址第一二字节为网络ID,后两个字节为主机ID,范围是128.0.0.0到191.255.255.255; 默认子网掩码:255.255.0.0;
  • C类地址前三个字节为网络ID,最后一个字节为主机ID,范围是192.0.0.0到223.255.255.255;默认子网掩码:255.255.255.0;
  • D类地址用于组播,前四位为1110,范围是224.0.0.0到239.255.255.255;
  • E类地址用于研究,前五位为11110,范围是240.0.0.0到247.255.255.255。

2、IP地址的两种表示方法:整数和点分十进制

点分十进制->整数:点分十进制->十六进制->十进制(整数)。

整数->点分十进制:十进制(整数)->十六进制->每个字节转换为十进制(整数)。

3、判断IP地址是否合法

  • IP的格式为:(1~255).(0~255).(0~255).(0~255)
  • 以小数点开头为非法IP,如:.x.x.x.或者.x.x.xx;
  • 以小数点结尾为非法IP,如:x.x.x.x.;
  • 输入带0开头为非法IP,如:0x.0xx.0x.00x。

四、IP地址转换

1、将点分十进制数串转换成 32 位无符号整数

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

2、将 32 位无符号整数转换成点分十进制数串

#include <arpa/inet.h>
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 缓存区长度;
  • #define INET_ADDRSTRLEN 16 // for ipv4
  • #define INET6_ADDRSTRLEN 46 // for ipv6
  • 返回值: 成功:则返回字符串的首地址,失败:返回 NULL