3.3 网络字节序 与 地址变换
3.3 网络字节序 与 地址变换
[!quote]
不同CPU中,数据在内存空间中的保存方式不同。
字节序 与 网络字节序
十六进制值0x12345678在内存中的存储长度为4字节,0x12为高位字节,0x78为低位字节
假设内存地址0x20~0x23存储该值
存储有两种方式:
大端(Big Endian):高位字节(0x12)存放在低位地址(0x20);低位字节存放在高位地址
小端(Little Endian):高位字节(0x12)存放在高位地址(0x23);低位字节存放在低位地址
| 内存地址 | 值(小) | 大端 |
|---|---|---|
| 0x23 | 0x12 | 0x78 |
| 0x22 | 0x34 | 0x56 |
| 0x21 | 0x56 | 0x34 |
| 0x20 | 0x78 | 0x12 |
按照地址顺序从低到高,按照大端字节序排序的数据和正常书写顺序相同,小端相反。小端存放的数据访问字节更方便。如向下转型,直接取低位字节。使用大端,进行转型,需要取高位字节。CPU运算是从低位地址开始的,和小端存储数据顺序相同。
主流的Intel系列CPU按小端字节序存储数据。
网络字节序
- 发送数据从保存在低位地址的数据开始传输
- 接收数据从低位地址开始存储

字节序不同的计算机之间进行通信,接收方接收后解析值和发送值不同。
问:书中图示中大端系统是从低地址开始传输,并从低地址开始存储,小端系统是否相同?
从结果看是这样的,小端系统解析为0x3412,所以低字节0x12存放在低地址。而0x12是先接收的,所以是从低地址向高地址存储。
问:网络传输数据是逐字节传输?
传输0x1234,两字节数据,但是数据是单个单个字节传输
[!quote]
在通过网络传输数据时约定统一方式,这种约定称为网络字节序。统一为大端序。即,先把数据数组转化成大端序格式再进行网络传输。
- 传输前将数据转换为大端序:先传输低地址内存数据,将高字节数据放到低地址内存
- 接收时是大端序接收:从MSB-最高有效字节开始接收,到LSB-最低有效字节结束

问:小端系统按大端序接收时,是否还是按照从低地址到高地址接收,然后再转换。还是改变接收方式:从高地址到低地址接收?
问:小端系统按照大端序发送时,是否将数据拷贝一份后转换为大端序,然后从低地址到高地址发送。还是直接从高地址到低地址传输?
问题的关键在于传输、接收的方式是否相同且不会发生改变:从低地址到高地址开始传输,从低地址到高地址开始接收。
从上图中开起来改变接收方式的方法比较简单。如果接收方式不变,网络传输的是字节流,对于两个十六进制数:0x1234、0x5678,接收后如何判断改变顺序的范围?调换0x12、0x34的顺序,而不是0x12、0x34、0x56、0x78 的顺序?
字节序转换
//port
unsigned short htons(unsigned short);
unsigned short ntohs(unsigned short);
//address
unsigned long htonl(unsigned long);
unsigned long ntohl(unsigned long);| 行号 | 功能 | 说明 |
|---|---|---|
| 2 | 用于端口的字节序转换,主机序转换为网络序 | h host:主机;n network:网络; s:short |
| 6-7 | 用于地址的转换 |
注
除了向sockaddr_in 结构体变量填充数据外,其他情况无需考虑字节序问题
补充:以及从sockaddr_in 结构体获取 网络字节序的地址 和 端口号