【Linux】网络编程基础(二):数据封装与网络传输流程

文章目录

    • 网络传输原理:数据如何在网络中旅行
    • 一、局域网通信原理
      • [1.1 两台主机在同一局域网能直接通信吗](#1.1 两台主机在同一局域网能直接通信吗)
      • [1.2 认识MAC地址](#1.2 认识MAC地址)
      • [1.3 以太网的通信规则](#1.3 以太网的通信规则)
      • [1.4 局域网通信的完整流程](#1.4 局域网通信的完整流程)
    • 二、数据封装与分用
      • [2.1 报文的组成](#2.1 报文的组成)
      • [2.2 不同层对报文的叫法](#2.2 不同层对报文的叫法)
      • [2.3 封装过程](#2.3 封装过程)
      • [2.4 分用过程](#2.4 分用过程)
      • [2.5 报头的作用](#2.5 报头的作用)
    • 三、认识IP地址
      • [3.1 为什么需要IP地址](#3.1 为什么需要IP地址)
      • [3.2 IP地址的格式](#3.2 IP地址的格式)
      • [3.3 IP地址的作用](#3.3 IP地址的作用)
    • 四、跨网络传输流程
      • [4.1 跨网络传输的问题](#4.1 跨网络传输的问题)
      • [4.2 路由器的作用](#4.2 路由器的作用)
      • [4.3 完整的跨网络传输流程](#4.3 完整的跨网络传输流程)
      • [4.4 IP地址和MAC地址的对比](#4.4 IP地址和MAC地址的对比)
    • 五、网络层的意义
      • [5.1 为什么需要网络层](#5.1 为什么需要网络层)
      • [5.2 IP网络的虚拟化](#5.2 IP网络的虚拟化)
      • [5.3 路由器的转发原理](#5.3 路由器的转发原理)
    • 六、封装与分用的宏观理解
      • [6.1 学习协议的两个关键问题](#6.1 学习协议的两个关键问题)
      • [6.2 数据传输的完整图示](#6.2 数据传输的完整图示)
      • [6.3 协议栈的分层处理](#6.3 协议栈的分层处理)
    • 七、本篇总结
      • [7.1 核心要点](#7.1 核心要点)
      • [7.2 容易混淆的点](#7.2 容易混淆的点)

网络传输原理:数据如何在网络中旅行

💬 开篇:上一篇我们理清了协议分层的框架,但数据到底怎么从一台主机传到另一台?局域网内的通信和跨网络的通信有什么区别?MAC地址和IP地址各自解决什么问题?这一篇会从数据封装的角度,带你看清数据在网络中的完整旅程。理解了封装和分用的过程,后面学习每一层的协议时,你就能把它们串起来。

👍 点赞、收藏与分享:这篇会讲清楚报文、报头、载荷这些核心概念,以及路由器在跨网络传输中的作用。如果对你有帮助,请点赞收藏!

🚀 循序渐进:从局域网通信到跨网络传输,从MAC地址到IP地址,一步步理解网络传输的完整流程。


一、局域网通信原理

1.1 两台主机在同一局域网能直接通信吗

答案是可以的。但这里有个前提:主机之间要能识别彼此。你在局域网里广播一条消息,所有主机都能收到,但怎么知道这条消息是不是发给自己的?

这就需要MAC地址。

1.2 认识MAC地址

MAC地址(Media Access Control Address)是数据链路层用来识别设备的唯一标识。每块网卡在出厂时就被分配了一个全球唯一的MAC地址,长度48位(6个字节),通常用16进制表示,比如 08:00:27:03:fb:19

MAC地址的作用:

  • 在局域网内标识设备的唯一性
  • 数据链路层通过MAC地址转发数据帧
  • 网卡收到数据帧后,检查目标MAC地址是否匹配,匹配就接收,不匹配就丢弃

这里要注意一点:虚拟机的MAC地址不是真实的MAC地址,可能会冲突。另外,某些网卡支持用户修改MAC地址,但正常情况下,物理网卡的MAC地址是全球唯一的。

1.3 以太网的通信规则

以下碰撞/CSMA/CD主要发生在共享介质或集线器(Hub)的半双工以太网;现代交换机+全双工以太网基本没有碰撞域。

以太网(Ethernet)是最常见的局域网类型。它有几个基本规则:

  1. 同一时刻只允许一台设备发送数据。如果多台设备同时发送,信号会相互干扰,这叫数据碰撞(Collision)。

  2. 碰撞检测和避免。发送数据的主机需要检测是否发生碰撞,如果检测到碰撞,就停止发送,等待一段随机时间后重试。

  3. 没有交换机的情况下,一个以太网就是一个碰撞域。所有设备共享同一个传输介质,任何两台设备同时发送都会发生碰撞。

  4. 广播方式。主机A要给主机B发送数据,实际上是把数据广播到整个局域网,所有主机都能收到,但只有目标MAC地址匹配的主机才会接收并处理。

这里可以从操作系统角度理解:网卡收到数据后,先检查目标MAC地址。如果不是发给自己的,直接丢弃;如果是发给自己的,就把数据交给上层协议栈处理。

1.4 局域网通信的完整流程

假设主机A(MAC地址:AA:AA:AA:AA:AA:AA)要给主机B(MAC地址:BB:BB:BB:BB:BB:BB)发送数据:

  1. 主机A的应用层产生数据
  2. 数据逐层向下传递,每一层都添加自己的报头
  3. 到达数据链路层时,添加以太网帧头(包含源MAC和目标MAC)
  4. 物理层把数据转换成电信号,发送到网线上
  5. 局域网内所有主机都收到这个信号
  6. 主机B的网卡检查目标MAC地址,发现是发给自己的,就接收
  7. 数据逐层向上传递,每一层剥掉自己的报头
  8. 最终应用层拿到原始数据

其他主机(主机C、主机D...)也收到了信号,但检查发现目标MAC不是自己,就直接丢弃了。

注意:现代交换机具备自学习算法:

首次通信:可能会因为 ARP 触发广播(广播帧所有主机都收到)

拿到 B 的 MAC 后:A 发给 B 的数据帧一般是 单播,交换机会根据 MAC 表只转发到 B 所在端口(其他主机收不到)


二、数据封装与分用

2.1 报文的组成

网络中传输的数据叫做报文(Message)。每个报文由两部分组成:

  • 报头(Header):协议规定的结构体字段,包含控制信息
  • 有效载荷(Payload):真正要传输的数据内容

报头就像快递单上的地址、电话、备注,载荷就是快递盒里的实际物品。

公式很简单:报文 = 报头 + 有效载荷

2.2 不同层对报文的叫法

不同的协议层对数据包有不同的称谓:

  • 应用层:数据(Data)或消息(Message)
  • 传输层:段(Segment),TCP段或UDP段
  • 网络层:数据报(Datagram)或分组(Packet)
  • 数据链路层:帧(Frame)
  • 物理层:比特流(Bit Stream)

这些名字只是约定俗成的叫法,本质都是"报头+载荷"的结构。

2.3 封装过程

数据从应用层向下传递时,每一层都会添加自己的报头,这个过程叫做封装(Encapsulation)。

以发送一封邮件为例:

  1. 应用层:邮件内容(原始数据)

  2. 传输层:添加TCP报头(源端口、目的端口、序列号...)

bash 复制代码
[TCP报头 | 邮件内容]
  1. 网络层:添加IP报头(源IP、目的IP、TTL...)
bash 复制代码
[IP报头 | TCP报头 | 邮件内容]
  1. 数据链路层:添加以太网帧头(源MAC、目的MAC...)和帧尾
bash 复制代码
[以太网帧头 | IP报头 | TCP报头 | 邮件内容 | 帧尾]
  1. 物理层:转换成比特流发送

每一层的报头都包含了该层需要的控制信息。比如TCP报头告诉对方"这是第几个数据包,要不要确认",IP报头告诉对方"我的地址是多少,你的地址是多少"。

2.4 分用过程

数据到达目标主机后,需要逐层向上传递,每一层剥掉自己的报头,这个过程叫做分用(Demultiplexing)或解封装。

bash 复制代码
接收端的处理过程:

1. 物理层收到比特流
2. 数据链路层检查以太网帧头,确认目标MAC是自己,剥掉帧头
3. 网络层检查IP报头,确认目标IP是自己,剥掉IP报头
4. 传输层检查TCP报头,根据目的端口号找到对应的进程,剥掉TCP报头
5. 应用层拿到邮件内容

关键问题:每一层怎么知道上层是什么协议?

答案在报头里。每一层的报头都有一个字段,标识上层协议的类型。比如:

  • 以太网帧头有"类型"字段,0x0800表示上层是IP协议
  • IP报头有"协议"字段,6表示上层是TCP,17表示上层是UDP
  • TCP/UDP报头有"目的端口号"字段,80表示HTTP,22表示SSH

这样,数据在向上传递时,每一层根据报头中的"上层协议"字段,就知道该把数据交给哪个上层协议处理。

2.5 报头的作用

报头里存放的是协议规定的控制信息。不同协议的报头内容不同,但作用类似:

  • 标识信息:源地址、目的地址、协议类型
  • 控制信息:序列号、确认号、标志位
  • 校验信息:校验和,用于检测数据是否损坏

报头是协议的核心。学习任何协议,最重要的就是搞清楚它的报头格式。后面我们学TCP、IP协议时,会详细分析每个报头字段的含义。


三、认识IP地址

3.1 为什么需要IP地址

MAC地址能在局域网内标识设备,为什么还要IP地址?

问题在于:MAC地址只能在局域网内使用。你的公司在北京,分公司在上海,两个局域网不直接相连,怎么让北京的主机找到上海的主机?

这就需要IP地址。IP地址是网络层的概念,用来在全球范围内标识主机。

3.2 IP地址的格式

IPv4地址是一个32位的整数,通常用"点分十进制"表示,比如 192.168.0.1。每个数字表示一个字节(8位),范围是0-255。

bash 复制代码
192.168.0.1
= 11000000.10101000.00000000.00000001 (二进制)
= 0xC0A80001 (十六进制)

IP地址有两个重要特点:

  1. 全球唯一性(公网IP)。互联网上的每个主机都有一个唯一的公网IP地址。当然,局域网内可以使用私网IP(如192.168.x.x),私网IP不是全球唯一的。

  2. 层次性。IP地址分为网络部分和主机部分,这样可以通过网络部分快速定位到目标网络,再通过主机部分找到具体主机。这和电话号码的区号+本地号码类似。

3.3 IP地址的作用

IP地址在网络层用来标识主机,路由器根据IP地址进行路径选择。

你可以这样理解:

  • MAC地址:局域网内的"门牌号",只在本地有效
  • IP地址:全球范围的"邮政编码+地址",可以跨网络使用

四、跨网络传输流程

4.1 跨网络传输的问题

局域网内通信很简单:主机A把数据广播出去,主机B根据MAC地址接收。但跨网络通信就复杂了:

  • 主机A在北京的局域网,主机B在上海的局域网
  • 两个局域网不直接相连,中间隔着多个路由器
  • 数据怎么从北京传到上海?

答案是:通过路由器逐跳转发。

4.2 路由器的作用

路由器(Router)工作在网络层,它的主要职责是:

  1. 路径选择:根据目的IP地址,查找路由表,决定数据应该从哪个接口转发出去
  2. 连接不同网络:路由器有多个网络接口,每个接口连接一个不同的网络
  3. 解包和重新封装:路由器收到数据后,剥掉数据链路层的帧头,查看IP报头,然后重新添加新的帧头转发

这里要理解一个关键点:路由器不转发帧,它转发的是数据报(IP报文)

具体来说:

  • 数据从主机A发出,到达路由器1
  • 路由器1剥掉以太网帧头(源MAC和目的MAC),只保留IP报文
  • 路由器1查看目的IP地址,决定从哪个接口转发
  • 路由器1添加新的以太网帧头(源MAC改为路由器1的MAC,目的MAC改为下一跳路由器的MAC)
  • 数据到达路由器2,重复上述过程
  • 最终数据到达目标主机B所在的局域网

4.3 完整的跨网络传输流程

假设主机A(IP:192.168.1.10)要给主机B(IP:10.0.0.20)发送数据,中间经过路由器R1和R2。

第一跳:主机A → 路由器R1

  1. 主机A封装数据:
bash 复制代码
[以太网帧头(源MAC=A, 目的MAC=R1) | IP报头(源IP=A, 目的IP=B) | TCP报头 | 数据]
  1. 路由器R1收到后:
  • 检查目的MAC是自己,接收
  • 剥掉以太网帧头
  • 查看IP报头的目的IP(B),查路由表,决定从接口2转发

第二跳:路由器R1 → 路由器R2

  1. 路由器R1重新封装:
bash 复制代码
[以太网帧头(源MAC=R1, 目的MAC=R2) | IP报头(源IP=A, 目的IP=B) | TCP报头 | 数据]

注意:源IP和目的IP始终是A和B。但以太网帧头变了,源MAC变成R1,目的MAC变成R2。

  1. 路由器R2收到后,重复上述过程

第三跳:路由器R2 → 主机B

  1. 路由器R2重新封装:
bash 复制代码
[以太网帧头(源MAC=R2, 目的MAC=B) | IP报头(源IP=A, 目的IP=B) | TCP报头 | 数据]
  1. 主机B收到后:
  • 检查目的MAC是自己,接收
  • 逐层解封装,最终应用层拿到数据

4.4 IP地址和MAC地址的对比

通过上面的流程,我们可以总结IP地址和MAC地址的区别:

特性 IP地址 MAC地址
作用范围 全球范围,可跨网络 局域网内,不可跨网络
变化性 在整个传输过程中不变 每经过一个路由器就变一次
作用 路径选择的依据 局域网转发的依据
层次 网络层 数据链路层

换句话说:

  • 目的IP地址是长远目标,决定了数据最终要去哪里
  • 目的MAC地址是阶段目标,决定了数据下一跳去哪里

主机A要给主机B发数据:

  • 目的IP始终是B,这是最终目标
  • 但目的MAC会变:先是R1(去往第一个路由器),然后是R2(去往第二个路由器),最后是B(到达目标主机)

五、网络层的意义

5.1 为什么需要网络层

我们已经有了数据链路层和MAC地址,为什么还要网络层和IP地址?

问题在于:世界上的网络类型有很多。以太网、WiFi、光纤、卫星链路,它们的底层实现完全不同。如果应用程序要直接面对这些差异,那每换一种网络类型,程序都要重写。

网络层的作用就是提供统一的抽象层,让上层协议(传输层、应用层)不需要关心底层网络的差异。

5.2 IP网络的虚拟化

IP协议让所有网络都变成"IP网络"。不管底层是以太网、WiFi还是光纤,在应用层看来都是一样的:

  • 发送方:把数据交给IP层,IP层负责选路和转发
  • 接收方:从IP层拿到数据,不需要知道底层是怎么传的

这种虚拟化的思想和操作系统的文件系统类似。你用fopen打开文件,不需要关心底层是机械硬盘还是固态硬盘,文件系统把这些差异屏蔽了。

5.3 路由器的转发原理

路由器维护一张路由表(Routing Table),记录 了"去往某个网络,应该从哪个接口转发"。

简化版路由表:

bash 复制代码
目的网络        下一跳          接口
10.0.0.0/8     192.168.1.1    eth0
172.16.0.0/12  192.168.1.2    eth1
0.0.0.0/0      192.168.1.254  eth0  (默认路由)

当路由器收到一个数据报时:

  1. 查看目的IP地址
  2. 在路由表中查找匹配的网络
  3. 从对应的接口转发出去
  4. 如果找不到匹配项,就用默认路由

这个过程叫做路由选择(Routing)。路由表可以是静态配置的,也可以通过路由协议(RIP、OSPF、BGP)动态学习。


六、封装与分用的宏观理解

6.1 学习协议的两个关键问题

从现在开始,我们学习任何协议,都要思考两个问题:

  1. 这个协议怎么解包的?

    • 报头格式是什么?
    • 每个字段的含义是什么?
    • 怎么判断报文是否合法?
  2. 这个协议怎么把数据交给上层的?

    • 报头中的哪个字段标识上层协议?
    • 怎么根据这个字段找到对应的上层处理函数?

只要搞清楚了解包和向上交付,封包的过程也就理解了。因为封包和解包是镜像的过程。

6.2 数据传输的完整图示

从主机A到主机B的数据传输:

bash 复制代码
主机A (应用层)
|
v
主机A (传输层) ← 添加TCP报头
|
v
主机A (网络层) ← 添加IP报头
|
v
主机A (数据链路层) ← 添加以太网帧头
|
v
主机A (物理层) → 发送到网络
|
v
路由器R1 (物理层) ← 接收
|
v
路由器R1 (数据链路层) ← 剥掉以太网帧头
|
v
路由器R1 (网络层) ← 查路由表,决定转发
|
v
路由器R1 (数据链路层) ← 添加新的以太网帧头
|
v
路由器R1 (物理层) → 发送到网络
|
v
... (可能经过多个路由器)
|
v
主机B (物理层) ← 接收
|
v
主机B (数据链路层) ← 剥掉以太网帧头
|
v
主机B (网络层) ← 剥掉IP报头
|
v
主机B (传输层) ← 剥掉TCP报头
|
v
主机B (应用层) ← 拿到原始数据

关键点:

  • 主机A和主机B都经过完整的五层协议栈
  • 路由器只经过三层(物理层、数据链路层、网络层)
  • IP报头在整个过程中保持不变
  • 以太网帧头每经过一个路由器就要重新封装

6.3 协议栈的分层处理

操作系统内核实现协议栈时,每一层都是一个独立的模块。数据在各层之间传递,每层只关心自己的报头:

c 复制代码
// 伪代码示意

// 发送端
void send_data(char *data, int len) {
    // 应用层
    char *app_data = data;
    
    // 传输层:添加TCP报头
    char *tcp_segment = add_tcp_header(app_data);
    
    // 网络层:添加IP报头
    char *ip_packet = add_ip_header(tcp_segment);
    
    // 数据链路层:添加以太网帧头
    char *eth_frame = add_eth_header(ip_packet);
    
    // 物理层:发送
    send_to_network(eth_frame);
}

// 接收端
void receive_data(char *frame) {
    // 数据链路层:检查并剥掉以太网帧头
    char *ip_packet = remove_eth_header(frame);
    
    // 网络层:检查并剥掉IP报头
    char *tcp_segment = remove_ip_header(ip_packet);
    
    // 传输层:检查并剥掉TCP报头
    char *app_data = remove_tcp_header(tcp_segment);
    
    // 应用层:处理数据
    process_data(app_data);
}

实际实现要复杂得多,但思路就是这样:逐层添加报头,逐层剥掉报头。


七、本篇总结

7.1 核心要点

局域网通信

  • MAC地址在数据链路层标识设备,全球唯一(物理网卡)
  • 以太网采用广播方式,主机根据目标MAC地址判断是否接收
  • 同一时刻只允许一台设备发送,多台同时发送会碰撞

数据封装与分用

  • 报文 = 报头 + 有效载荷
  • 封装:数据向下传递,每层添加自己的报头
  • 分用:数据向上传递,每层剥掉自己的报头
  • 报头中包含"上层协议"字段,用于分用时找到对应的上层处理函数

IP地址的作用

  • 网络层的地址,用于全球范围内标识主机
  • 32位整数,点分十进制表示(如192.168.0.1)
  • 具有层次性,分为网络部分和主机部分

跨网络传输

  • 路由器工作在网络层,连接不同网络
  • 路由器根据目的IP地址查路由表,决定转发路径
  • IP报头在整个传输过程中保持不变
  • MAC地址每经过一个路由器就要重新封装

IP地址 vs MAC地址

  • IP地址:长远目标,决定最终去哪里,不变
  • MAC地址:阶段目标,决定下一跳去哪里,每跳都变

网络层的意义

  • 提供统一的抽象层,屏蔽底层网络的差异
  • 让世界上所有网络都变成"IP网络"
  • 类似操作系统的文件系统,屏蔽磁盘类型的差异

7.2 容易混淆的点

  1. MAC地址只在局域网内有效:不要以为MAC地址能跨网络使用。跨网络传输时,MAC地址会不断变化,IP地址才是始终不变的。

  2. 路由器不转发帧:路由器转发的是IP数据报,它会剥掉原来的帧头,重新添加新的帧头。这是因为不同网络的帧格式可能不同(以太网、WiFi、光纤)。

  3. 封装和分用是镜像过程:发送端逐层添加报头,接收端逐层剥掉报头。理解了一个,另一个也就理解了。

  4. 目的IP不变,目的MAC一直在变:这是理解跨网络传输的关键。目的IP是最终目标,目的MAC是下一跳目标。类比一下:你从北京坐飞机到上海,"上海"是最终目的地(IP),但你要先去机场(第一跳的MAC),再上飞机(第二跳的MAC),最后到上海机场(第三跳的MAC)。

  5. 学习协议的方法:先搞清楚解包的过程(报头格式、字段含义),再搞清楚向上交付的机制(上层协议字段)。封包的过程就是解包的逆过程。


💬 总结:这一篇把网络传输的完整流程讲清楚了。从局域网通信到跨网络传输,从MAC地址到IP地址,从封装到分用,这些是理解网络协议的基础。后面我们会深入讲解每一层的具体协议,比如以太网帧格式、IP报文格式、TCP报文格式,但核心思路都是这样:报头定义了协议的规则,封装和分用实现了数据的传递。
👍 点赞、收藏与分享:如果这篇文章帮你理清了网络传输的流程,请点赞收藏!下一篇我们会讲Socket编程的预备知识,包括端口号、网络字节序、Socket API。

相关推荐
2301_822366352 小时前
C++中的命令模式变体
开发语言·c++·算法
柱子jason2 小时前
使用IOT-Tree Server模拟Modbus设备对接西门子PLC S7-200
网络·物联网·自动化·modbus·西门子plc·iot-tree·协议转换
久绊A2 小时前
春节前云平台运维深度巡检-实操经验
运维·安全·容器·kubernetes·云平台
每天要多喝水2 小时前
nlohmann/json 的使用
c++·json
万邦科技Lafite3 小时前
一键获取京东商品评论信息,item_reviewAPI接口指南
java·服务器·数据库·开放api·淘宝开放平台·京东开放平台
旅途中的宽~3 小时前
【深度学习】通过nohup后台运行训练命令后,如何通过日志文件反向查找并终止进程?
linux·深度学习
蓁蓁啊3 小时前
C/C++编译链接全解析——gcc/g++与ld链接器使用误区
java·c语言·开发语言·c++·物联网
梦想的旅途23 小时前
企业微信API外部群自动化推送:从“群发工具”到“智能触达”的架构实践
运维·自动化·企业微信
yuezhilangniao3 小时前
Next.js 项目运维手册-含-常用命令-常见场景
运维·开发语言·reactjs