首先讲述了网络字节序和本地字节序的概念,并且交代了基本的字节序转换函数。
目录
一.网络字节序与本地字节序
二.字节序转换函数
一.网络字节序与本地字节序
字节序(Byte Order)指的是多字节数据在内存中的存储顺序。分为两种:
????????????????????????????????????1.小端字节序? ? ? ? ? 2.大端字节序
在说明两者区别之前,我们必须要明白,计算机所谓的数据,实际上存在两种形式:
字符形式(也称展示形式)和二进制形式(也称数据形式)。 二进制形式是计算机存储和处理数据时使用(或说看待)数据的形式,而字符形式是人与计算机交互时使用(或说看待)数据的形式。
最直观的例子是键盘。
键盘上的符号,比如'A','4',')'这些人直观能够看到的数据,就是以字符形式(也可以称为展示形式)存在的;
而当人键入一个字符,比如'd'时,计算机会把它视为01100100这样的二进制序列。
那么对于展示形式为"192.55.0.2"这样的多字节数据,计算机会怎样存储呢?
我们知道,"192.55.0.2"是IP地址的展示形式(点分十进制形式)。我们忽略点号(.),只关注十进制数部分。
这样的数据的二进制形式为11000000 00110111 00000000 00000010。
我们假设我们有连续的4 byte的内存单元(由小到大为:0XAAAA, 0XAAB2, 0XAABA, 0XAAC2)。问题是我们该以怎样的顺序存放上面的四个字节的数据呢?是把高位的数据(192d or 11000000b)放入高位的内存单元(0XAAC2),还是放入低位的内存单元(0XAAAA)?
依照不同的存储顺序,本地字节序(host?byte order)分为小端字节序和大端字节序。本地字节序指的是本机存储连续字节数据的顺序。小端字节序指的是低位字节存入低位内存,高位字节存入高位内存的存储方式;大端字节序反之,将低位字节存入高位内存,将高位字节存入低位内存。
内存单元(从低位到高位) AAAA AAB2 AABA AAC2
小端字节序 2 0 55 192
大端字节序 192 55 0 2
那么网络字节序又是怎么来的呢?
实际上网络字节序(Network Byte Order)就是网络中间设备(比如路由器)的本地字节序。
一般而言,网络字节序采用大端字节序,本地字节序采取小段字节序。
二.字节序转换函数
由于网络字节序和本地字节序(叫主机字节序也可以)的客观存在,我们在进行网络编程时为了增强程序的可移植性都会使用字节序转换函数来转换字节序。?
库 | 函数原型 | 解释 | 作用 | <arpa/inet.h> | uint32_t htonl(uint32_t hostlong); | htonl=host_to_network_long hostlong:4 byte的本地字节序的数据。 | 由于ipv4的IP地址为32位,所以这个函数往往用于把本地字节序的IP地址转换为网络字节序。 | ~ | uint16_t htons(uint16_t hostshort); | htons=host_to_network_short hostshort:2字节的本地字节序的数据。 | 由于端口号为16位,所以这个函数往往用于把本地字节序的port数转化为网络字节序。 | ~ | uint32_t ntohl(uint32_t netlong); | ntohl=network_to_host_long netlong:4字节的网络字节序的数据。 | 作用和htonl相反 | ~ | uint16_t ntohs(uint16_t netshort); | ntohs=network_to_host_short | 作用和htons相反 | uint32_t:32位无符号整型数。u为unsigned,t为typedef(表示这个数据类型是由宏定义得到的)。其它uint**_t同理。 man ntol: 在Linux命令行中输入该命令,打开对应的手册。 |
使用上面的函数时,需要注意转换IP地址时的情况。我们习惯上使用IP地址的展现形式:点分十进制形式(使用字符数组存储),如"192.55.0.2"。而hostlong需要的是一个uint32_t型的数据,所以我们还需要先把字符数组形式的IP地址转化为32位无符号整型才可以。比较麻烦。
所以可以考虑直接使用下列函数:
<arpa/inet.h> | int inet_pton(int af, const char *src, void *dst); | inet_pton=internet_ presentation_to_numerical af: 可选值为AF_INET或是AF_INET6(分别表明带转换的点分十进制IP地址为ipv4或是ipv6) src: 点分十进制形式的IP地址所在的字符数组 dst:数值形式的IP地址所在整型的地址 | 将点分十进制(字符串)的ipv4/ipv6地址转化为数值形式、网络字节序的IP地址存储在整形中。 | ~ | const char *inet_ntop(int af, const void *src, char *dst, socklen_t size); | src: 点分十进制形式的IP地址所在的字符数组 dst:数值形式的IP地址所在整型的地址 size:dst的大小 return:成功,返回dst;失败,返回NULL。 | 反之 |
可以在Linux命令行中键入:man inet_pton查看详细信息。
#include <arpa/inet.h>
#include <stdio.h>
int main(){
char ip_local[20] = "192.55.0.2";
long ip_network = 1;
int a = inet_pton(AF_INET,ip_local,(void *)&ip_network);
printf("%d\n%s\n%ld\n",a,ip_local,ip_network);
return 0;
}
//可以发现最后打印的结果为33568704
/*
192.55.0.2
11000000 00110111 00000000 00000010
3356874
00000010 00000000 00110111 11000000
两者的字节呈反序。
*/
|