网络字节序和主机序(大端和小端)详细解释--通过封装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;

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


相关文章
|
9月前
|
JavaScript
Vue中Axios网络请求封装-企业最常用封装模式
本教程介绍如何安装并配置 Axios 实例,包含请求与响应拦截器,实现自动携带 Token、错误提示及登录状态管理,适用于 Vue 项目。
358 1
|
8月前
|
网络协议 Linux 虚拟化
配置VM网络:如何设定静态IP以访问主机IP和互联网
以上就是设定虚拟机网络和静态IP地址的基本步骤。需要注意的是,这些步骤可能会因为虚拟机软件、操作系统以及网络环境的不同而有所差异。在进行设定时,应根据具体情况进行调整。
584 10
|
负载均衡 网络协议 网络性能优化
动态IP代理技术详解及网络性能优化
动态IP代理技术通过灵活更换IP地址,广泛应用于数据采集、网络安全测试等领域。本文详细解析其工作原理,涵盖HTTP、SOCKS代理及代理池的实现方法,并提供代码示例。同时探讨配置动态代理IP后如何通过智能调度、负载均衡、优化协议选择等方式提升网络性能,确保高效稳定的网络访问。
1913 2
|
11月前
|
监控 安全 Go
使用Go语言构建网络IP层安全防护
在Go语言中构建网络IP层安全防护是一项需求明确的任务,考虑到高性能、并发和跨平台的优势,Go是构建此类安全系统的合适选择。通过紧密遵循上述步骤并结合最佳实践,可以构建一个强大的网络防护系统,以保障数字环境的安全完整。
234 12
|
监控 安全 网络安全
网络安全新姿势:多IP配置的五大好处
服务器配置多IP地址,既能提升网络速度与安全性,又能实现多站点托管和故障转移。本文详解多IP的五大妙用、配置方法及进阶技巧。从理论到实践,合理规划IP资源,让服务器性能跃升新高度。
366 2
|
域名解析 API PHP
VM虚拟机全版本网盘+免费本地网络穿透端口映射实时同步动态家庭IP教程
本文介绍了如何通过网络穿透技术让公网直接访问家庭电脑,充分发挥本地硬件性能。相比第三方服务受限于转发带宽,此方法利用自家宽带实现更高效率。文章详细讲解了端口映射教程,包括不同网络环境(仅光猫、光猫+路由器)下的设置步骤,并提供实时同步动态IP的两种方案:自建服务器或使用三方API接口。最后附上VM虚拟机全版本下载链接,便于用户在穿透后将服务运行于虚拟环境中,提升安全性与适用性。
1081 7
|
安全 网络安全 UED
为何长效代理静态IP是网络管理的关键要素
在信息化时代,静态长效IP代理对网络管理至关重要。它能提升网络服务质量,确保远程办公、视频会议等应用的稳定性和连续性;减少延迟和网络拥堵,加快数据传输;提高网络安全,便于设置访问权限,防止未授权访问。91HTTP高质量代理IP服务商助力高效信息获取。
336 23
|
安全 网络协议 Java
Java网络编程封装
Java网络编程封装原理旨在隐藏底层通信细节,提供简洁、安全的高层接口。通过简化开发、提高安全性和增强可维护性,封装使开发者能更高效地进行网络应用开发。常见的封装层次包括套接字层(如Socket和ServerSocket类),以及更高层次的HTTP请求封装(如RestTemplate)。示例代码展示了如何使用RestTemplate简化HTTP请求的发送与处理,确保代码清晰易维护。
|
网络协议 Unix Linux
深入解析:Linux网络配置工具ifconfig与ip命令的全面对比
虽然 `ifconfig`作为一个经典的网络配置工具,简单易用,但其功能已经不能满足现代网络配置的需求。相比之下,`ip`命令不仅功能全面,而且提供了一致且简洁的语法,适用于各种网络配置场景。因此,在实际使用中,推荐逐步过渡到 `ip`命令,以更好地适应现代网络管理需求。
862 11