说在前面
- 环境: WSL
- 参考: UNIX网络编程
大小端
-
定义
小端字节序:将低序字节存储在起始地址。
大端字节序:将高序字节存储在起始地址。
图一 “大端”和“小端”表示将多个字节值的哪一端(小端即低位,
就比如一个三位数的个位数;大端即高位,就比如一个三位数的百位)存储在该值的起始位置。主机序:某个给定系统(例如windows或者ubuntu)所使用的字节序。
-
程序确定
-
通常使用联合体(union)来确定某个系统所使用的字节序。
union{ short s; char c[sizeof(short)]; } un;
我们令un.s=0x0102,然后查看字符数组c的取值来确定其字节序(如图一)。
-
code
#include <stdio.h> int main() { union{ short s; char c[sizeof(short)]; } un; un.s = 0x0102; printf("system : "); // 书中的CPU_VENDOR_OS是在config.h中定义的 // 而这个config.h是由config.h.in生成的,这里就不使用了 //在某些系统中,short并不是2字节 if(sizeof(short) == 2){ if(un.c[0] == 1 && un.c[1] == 2) printf("big-endian\n"); else if(un.c[0] == 2 && un.c[1] == 1) printf("little-endian\n"); else printf("unknow\n"); } else { printf("sizeof(short) = %d\n", sizeof(short)); } }
-
网络字节序
- 网际协议使用大端字节序来传送多字节值。
字节排序函数
//头文件
#include <netinet/in.h>
//主机字节序转换为网络字节序
uint16_t htons(uint16_t host16bitvalue);
uint32_t htonl(uint32_t host32bitvalue);
//网络字节序转换为主机字节序
uint16_t ntohs(uint16_t net16bitvalue);
uint32_t ntohl(uint32_t net32bitvalue);
- 在这些函数的名称中,h表示host,n表示network,s代表short,l代表long(历史遗留)。现在s通常代表16位值,l代表32位值。
- 在使用这些函数时,我们并不需要关心主机字节序的具体值(大端还是小端),我们只需要调用他们并转换我们需要用到的值。
位序
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|Version| IHL |Type of Service| Total Length |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- 如上图IPv4首部4字节,它表示按照在线缆上出现的顺序排列的四个字节,最左边是最早出现的最高有效位。
- 什么叫做在“线缆上出现”?
如下图,同样以IPv4首部4字节(32位)为例,那么在接收时我们将先得到Version字段(比如Version字段为0100,那么先得到0,然后1,而后0,最后0)