网络字节序和主机序(大端和小端)详细解释--通过封装IP协议头去理解网络字节序

简介: 网络字节序和主机序(大端和小端)详细解释--通过封装IP协议头去理解网络字节序

一、什么是大端和小端?

小端:低位数据放在低地址

大端:高位数据放在低地址

比如 0x12 34 56 78,其中78是低位,12是高位。该数的右侧是低地址,左侧是高地址。也就是说低位对应低地址(小端字节序)

如果0x12 34 56 78是小端字节序,那么0x78 56 34 12就是大端字节序,它把高位12放在最右侧的低地址(大端字节序)

一般,

主机字节序小端模式

网络字节序大端模式

而一个字节中的比特序,是低位放在低地址的。

为什么要有大端小端之分?

小端: 在内存中通常低位放在低地址。比如说0x12 34 56 78,从右往左,这样使得程序处理速度更快。

大端:网络字节序,0x78 56 34 12将字节序反了一下。

但是一般人们阅读习惯就是从左往右。举个例子,对于网络字节序0x78 56 34 12,网络通常以字节流的方式传输,先接受到的是低地址的12,接着是34,…这样就能接收到的顺序就是12345678,也就是正常的顺序。如果直接按照0x12 34 56 78进行传输,会先接受到78然后是56…这个样子显然是不方便人为的阅读。

看了一堆文字,可能会觉得很抽象,不如动手验证下。

下面将会验证主机序是小端字节序,并且会以IP协议头为例,更好地去解释大端模式的网络字节序。

二、主机序:小端模式

1、验证主机的字节序

num=0xff00ff00通过memcpy拷贝到struct MyInt看看内存地址是如何分布的

struct MyInt{
    unsigned char F1;//低地址
    unsigned char F2;
    unsigned char F3;
    unsigned char F4;//高地址
};
void test1(){
    MyInt* myint=(MyInt*)malloc(sizeof(MyInt));
    unsigned int num=0xff00ff00;
    memcpy((void*)myint,(void*)&num,sizeof(int));
    cout<<"num:"<<std::hex<<num<<endl;
    cout<<"F1:"<<std::hex<<(int)myint->F1<<endl;
    cout<<"F2:"<<std::hex<<(int)myint->F2<<endl;
    cout<<"F3:"<<std::hex<<(int)myint->F3<<endl;
    cout<<"F4:"<<std::hex<<(int)myint->F4<<endl;
}
int main(){
    test1();
    system("pause");
}

运行结果

可以看到F1是低地址 对应 低位,F4是高地址 对应 高位,也就是说 主机序是小端字节序

2、查看比特序

进行略微修改,通过位域操作,将 F1的一个字节,拆分成两个半字节(4比特),来验证下比特序

struct MyInt{
    unsigned char F11:4,
                    F12:4;
    unsigned char F2;
    unsigned char F3;
    unsigned char F4;//高地址
};
void test1(){
    MyInt* myint=(MyInt*)malloc(sizeof(MyInt));
    unsigned int num=0xff00ff0f;//0xff00ff00改为0xff00ff0f
    memcpy((void*)myint,(void*)&num,sizeof(int));
    cout<<"num:"<<std::hex<<num<<endl;
    cout<<"F11:"<<std::hex<<(int)myint->F11<<endl;
    cout<<"F12:"<<std::hex<<(int)myint->F12<<endl;
    cout<<"F2:"<<std::hex<<(int)myint->F2<<endl;
    cout<<"F3:"<<std::hex<<(int)myint->F3<<endl;
    cout<<"F4:"<<std::hex<<(int)myint->F4<<endl;
}
int main(){
    test1();
    system("pause");
}

运行结果

可以看到 F11的地址比F12的地址更低,由此可见,在比特位 的低位 在低地址

3、主机序总结

对于主机序,低位字节 在低地址,因此是小端字节序。

同时,比特序,低位 在 低地址。

三、网络序

如果 0x12 34 56 78 是小端序,那么大端序就是0x78 56 34 12(也就是网络字节序)

在发送或者接受到的数据,都必须要是网络字节序的。

1、以IP协议头为例

左上角为高位,右下角为低位,以这种方式组装成数据帧,在网络中进行发送。

可以通过定义一个结构体,存放协议头中每个标签。

struct iphdr {
  unsigned char hdrlen:4,    
          version:4;       
  unsigned char tos;//type of service
  unsigned short totlen;//total length
  unsigned short id;//16位标识
  unsigned short flag_offset; //3位标志+13位片偏移
  unsigned char ttl; //time to live 生存周期(比如:每经过一个网关ttl-1)
  // 0x1234// htons
  unsigned char type;//8位协议  用于指明IP的上层协议.
  unsigned short check;//16位首部校验和
  unsigned int sip;//源ip
  unsigned int dip;//目的ip
}; // 20字节

为什么要用结构体?

因为结构体起始是低地址,低地址协议头的高位,那么不就是大端模式了嘛。

接下去,还有一步骤没有做,就是将数据帧iphdr+数据 等内容通过memcpy的方式加入到 发送缓冲char* buffer中去,低地址 依然 放的高位不会变。

通过memcpy,可以将version和hdrlen拷贝到最右侧(只是为了分析字节序,所以不考虑以太网头等内容)。

那样对于高位的version和hdrlen 不就是在低地址了吗(高位在低地址,也就是 大端字节序)

因此协议头的高位在在char* buffer中的低地址处,因此是网络字节序,这种网络字节序的请求,可以被服务端所解析。

2、字节中的比特序

为什么 hdrlen(header len 首部长度)是高位呢?而不是version(4位版本)是高位?

因为网络字节序是按字节为单位的,发送的是字节流,char* 作为类型,无论是服务端或者客户端,都只对数据进行解包和打包,char*作为一个基本单位,因此不会再去继续分。

也就是说,不会涉及比一个char* 更小的操作,那么 比特序只要和主机端的比特序一致就行了,也就是说低地址放低比特位,于是可知hdrlen相比version是低位,因此放在前面。

但是在用结构体 定义协议头的时候,为了结构清晰,一般会用域操作细分。

unsigned char hdrlen:4,    
        version:4;

可以看到高位放在低地址中,也就是大端模式。


相关文章
|
2月前
|
域名解析 存储 网络协议
深入解析网络通信关键要素:IP 协议、DNS 及相关技术
本文详细介绍了IP协议报头结构及其各字段的功能,包括版本、首部长度、服务类型、总长度、标识、片偏移、标志、生存时间(TTL)、协议、首部检验和等内容。此外,还探讨了IP地址的网段划分、特殊IP地址的应用场景,以及路由选择的大致流程。最后,文章简要介绍了DNS协议的作用及其发展历史,解释了域名解析系统的工作原理。
123 5
深入解析网络通信关键要素:IP 协议、DNS 及相关技术
|
6天前
|
网络协议 网络安全 数据安全/隐私保护
计算机网络概念:网关,DHCP,IP寻址,ARP欺骗,路由,DDOS等
计算机网络概念:网关,DHCP,IP寻址,ARP欺骗,路由,DDOS等
26 4
|
8天前
|
网络协议 定位技术 网络架构
IP 路由:网络世界的导航仪
IP 路由:网络世界的导航仪
21 3
|
16天前
|
网络协议 网络安全 数据安全/隐私保护
计算机网络概念:网关,DHCP,IP寻址,ARP欺骗,路由,DDOS等
【10月更文挑战第27天】计算机主机网关的作用类似于小区传达室的李大爷,负责将内部网络的请求转发到外部网络。当小区内的小不点想与外面的小明通话时,必须通过李大爷(网关)进行联系。网关不仅帮助内部设备与外部通信,还负责路由选择,确保数据包高效传输。此外,网关还参与路由表的维护和更新,确保网络路径的准确性。
39 2
|
17天前
|
存储 缓存 Dart
Flutter&鸿蒙next 封装 Dio 网络请求详解:登录身份验证与免登录缓存
本文详细介绍了如何在 Flutter 中使用 Dio 封装网络请求,实现用户登录身份验证及免登录缓存功能。首先在 `pubspec.yaml` 中添加 Dio 和 `shared_preferences` 依赖,然后创建 `NetworkService` 类封装 Dio 的功能,包括请求拦截、响应拦截、Token 存储和登录请求。最后,通过一个登录界面示例展示了如何在实际应用中使用 `NetworkService` 进行身份验证。希望本文能帮助你在 Flutter 中更好地处理网络请求和用户认证。
133 1
|
1月前
|
网络协议 Java 程序员
【网络】局域网LAN、广域网WAN、TCP/IP协议、封装和分用
【网络】局域网LAN、广域网WAN、TCP/IP协议、封装和分用
32 2
|
25天前
|
存储 缓存 Ubuntu
配置网络接口的“IP”命令10个
【10月更文挑战第18天】配置网络接口的“IP”命令10个
48 0
|
1月前
|
运维 安全 网络协议
Python 网络编程:端口检测与IP解析
本文介绍了使用Python进行网络编程的两个重要技能:检查端口状态和根据IP地址解析主机名。通过`socket`库实现端口扫描和主机名解析的功能,并提供了详细的示例代码。文章最后还展示了如何整合这两部分代码,实现一个简单的命令行端口扫描器,适用于网络故障排查和安全审计。
|
2月前
|
缓存 网络协议 网络架构
网络抓包分析【IP,ICMP,ARP】以及 IP数据报,MAC帧,ICMP报和ARP报的数据报格式
本文详细介绍了如何使用网络抓包工具Wireshark进行网络抓包分析,包括以太网v2 MAC帧、IP数据报、ICMP报文和ARP报文的格式,以及不同网络通信的过程。文章通过抓包分析展示了IP数据报、ICMP数据报和ARP数据报的具体信息,包括MAC地址、IP地址、ICMP类型和代码、以及ARP的硬件类型、协议类型、操作类型等。通过这些分析,可以更好地理解网络协议的工作机制和数据传输过程。
网络抓包分析【IP,ICMP,ARP】以及 IP数据报,MAC帧,ICMP报和ARP报的数据报格式
|
2月前
|
网络协议 网络虚拟化
接收网络包的过程——从硬件网卡解析到IP
【9月更文挑战第18天】这段内容详细描述了网络包接收过程中机制。当网络包触发中断后,内核处理完这批网络包,会进入主动轮询模式,持续处理后续到来的包,直至处理间隙返回其他任务,从而减少中断次数,提高处理效率。此机制涉及网卡驱动初始化时注册轮询函数,通过软中断触发后续处理,并逐步深入内核网络协议栈,最终到达TCP层。整个接收流程分为多个层次,包括DMA技术存入Ring Buffer、中断通知CPU、软中断处理、以及进入内核网络协议栈等多个步骤。

热门文章

最新文章