一、网络字节序
1、大端模式和小端模式
字节序是指多字节数据的存储顺序,在设计计算机系统的时候,有两种处理内存中数据的方法:大端格式、小端格式。
小端格式(Little-Endian):将低位字节数据存储在低地址;
大端格式(Big-Endian):将高位字节数据存储在低地址。
举个简单的例子,对于整形 0x12345678,它在大端格式和小端格式的系统中,分别如下图所示的方式存放:
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:
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