Linux网络编程(二):网络数据传输基本流程

目录

一、局域网

[1. 为什么从局域网开始](#1. 为什么从局域网开始)

[2. 局域网通信例子](#2. 局域网通信例子)

[二、MAC 地址](#二、MAC 地址)

[1. 什么是 MAC 地址](#1. 什么是 MAC 地址)

[2. 数据碰撞](#2. 数据碰撞)

[3. 同一网段通信流程](#3. 同一网段通信流程)

三、封装与分用

[1. 报头、载荷与报文](#1. 报头、载荷与报文)

[2. 段、报、帧](#2. 段、报、帧)

[3. 封装过程](#3. 封装过程)

[4. 分用过程](#4. 分用过程)

四、跨网络通信

[1. 为什么需要 IP 地址](#1. 为什么需要 IP 地址)

[2. IP 地址](#2. IP 地址)

[3. 路由转发](#3. 路由转发)

[4. IP 与 MAC 的区别](#4. IP 与 MAC 的区别)

[5. IP 层屏蔽底层差异](#5. IP 层屏蔽底层差异)

总结


一、局域网

在前文中,我们明确了协议的本质是结构化数据。然而,数据仅在内存中有序排列是不够的,它还需要穿越复杂的网络环境------包括电缆、路由器和交换机等设备------最终到达目标机器

本篇将从最基础的局域网(LAN)开始,逐步解析数据包如何在物理介质上实现 "第一跳" 传输


1. 为什么从局域网开始

网络通信遵循 "分而治之" 和 "局部连接" 的原则。实际上,无论数据包的目的地是哪,它离开发送端主机的第一步,都是在局域网内完成的。局域网是构成全球互联网的最小细胞,理解了局域网的内部通信,跨网络通信也就只是多个局域网之间的接力跳跃而已

以太网

在局域网的众多实现技术中,以太网占据着无可争议的主导地位

  • 本质:以太网不仅仅指我们平时插的网线,它是一套完整的局域网通信标准(主要对应 OSI 模型中的物理层和数据链路层)

  • 特性 :以太网的核心是一种广播式的通信方式。在同一个局域网内的所有主机,物理上都连接在同一个共享的通信介质(比如早期的总线或现在的交换机)上


2. 局域网通信例子

为了直观理解局域网的工作模式,我们可以看一个现实生活中的经典场景

想象一下,在一个有 50 名学生的教室里:

  • 环境即媒介:教室里的空气就是通信介质,每个人的耳朵都在实时监听

  • 广播发送:老师大声喊了一句:张三,把你写的作业交上来!

  • 目标识别与过滤

    • 全体接收 :由于声音在空气中传播,教室内所有学生 其实都听到了这句话。这在网络中被称为广播

    • 静默过滤:李四听到了,但他发现目标名字是 "张三" 而不是自己,于是他选择忽略,不予响应

    • 精准响应:张三听到了,发现名字匹配成功,于是他站起来(做出响应)并将作业(数据载荷)交给老师

在这个例子中,"张三" 这个名字就充当了网络中的地址标识 。在局域网的底层,这个标识就是我们下一节要讲的 MAC 地址

二、MAC 地址

在局域网中如果所有设备都无序地发送信号,通信很快就会陷入混乱。为了确保通信有序进行,我们需要为每个网络设备分配唯一的标识符,并建立规范的通信协议


1. 什么是 MAC 地址

MAC 地址(Media Access Control Address),直译为媒体存取控制地址,它是网卡的物理身份证。它工作在数据链路层,负责在局域网内部精确地寻找目标

  • 唯一性:每一块网卡在出厂时,都会被烧录一个全球唯一的 MAC 地址

  • 格式:由 48 位二进制组成,通常用 12 位十六进制数表示(如 00:0c:29:4f:8b:36)

注意:MAC 地址和你的地理位置无关。无论你把电脑带到北京还是纽约,网卡的 MAC 地址永远不变,它唯一标识的是 "设备身份",而非 "物理位置"


2. 数据碰撞

什么是数据碰撞?

从网络传输的角度看,局域网(特别是早期的总线型网络)就像是一条单行道 ,但在同一时间内,这条路只允许一辆车(一个数据包)通行

产生原因

在逻辑上,我们把这种多台设备连接在同一根线上的结构称为共享介质

  • 逻辑矛盾:当主机 A 认为线路空闲并开始发送报文时,主机 B 可能几乎在同一瞬间也认为线路空闲并发送了报文

  • 数据损毁 :这两个报文在逻辑链路上发生碰撞。在接收方看来,收到的不再是完整的以太网帧,而是一串破碎的、无法校验通过的乱码

为了解决这个问题,诞生了两个重要的机制:

  1. CSMA/CD:这是一种 "先听后发" 的礼貌通信机制。设备在发送数据前会先检测信道是否空闲;若在传输过程中检测到冲突,则会立即停止发送,等待一段随机时间后重新尝试

  2. 交换机 : 现代局域网已基本淘汰这种 "广播式" 通信模式。交换机会利用内置的 MAC 地址表,将数据精准地从发送方传输至接收方,有效避免了数据碰撞,使每台设备都能实现 "点对点" 通信


3. 同一网段通信流程

这是局域网通信最经典的过程。假设主机 A 要给主机 B 发送数据,而它们处于同一个局域网内:

(1) 封装报文

主机 A 会构建一个以太网帧。在这个帧的头部,它会填入:

  • 源 MAC 地址:A 自己的地址

  • 目标 MAC 地址:B 的地址

  • 数据载荷:真正要传输的内容

(2) 广播传输

虽然数据是发给 B 的,但物理信号会顺着电缆传送到局域网内的每一台主机(或者发给交换机由其扩散/转发)

(3) 硬件过滤

这是最关键的一步。局域网内的所有主机(C、D、E...)的网卡都会收到这个信号:

  • 主机 C :网卡读取帧头部的 "目标 MAC",发现不是自己,直接丢弃。CPU 完全感知不到有数据包经过,没有任何系统开销

  • 主机 D:同上,丢弃

  • 主机 B:网卡发现 "目标 MAC" 与自己的 MAC 地址完全匹配!

(4) 接收并上报

主机 B 的网卡确认身份后,会剥离掉以太网帧的报头,将剩余的有效载荷(Data)向上递交给操作系统处理

三、封装与分用

掌握了局域网的 "交通规则" 后,让我们来看看数据在传输前是如何 "包装" 的。在网络通信中,数据不会以原始状态传输,必须经过精密的封装处理


1. 报头、载荷与报文

报头是协议栈每一层在处理数据时额外添加的控制信息

  • 现实类比 :报头就像是快递盒上贴的那张面单。上面写着发件人、收件人、包裹重量、是否易碎、快递单号等。快递员不关心盒子里装的是什么,他只看面单上的地址来决定往哪送

  • 技术本质:在 Linux 内核中,报头通常是一个定义的结构体。它包含了目标地址、源地址、协议类型、校验和等关键元数据

载荷(也叫有效载荷)是指被协议包裹的真实数据

  • 现实类比 :载荷就是你真正寄给朋友的那件衬衫。对于快递公司来说,衬衫是载荷;对于收件人来说,衬衫才是他真正想要的东西

  • 嵌套关系 :这是一个非常关键的逻辑------上一层的完整报文,是下一层的载荷

    • 就像你把衬衫(载荷)装进礼品盒(报头 1),然后快递公司把整个礼品盒放入了一个更大的运输纸箱(报头 2)。对运输纸箱来说,里面的礼品盒整体就是它的载荷

报文 是对网络传输中一个完整数据单元的通用称呼

在应用层、传输层和网络层中,这些传输的数据统称为 "报文"。不过,为了体现各层的功能特性,工程师们为不同层级的报文赋予了专门的术语名称


2. 段、报、帧

在 TCP/IP 五层模型中,每一层产出的报文都有一个专属称谓

层次 报文称谓 英文名 说明
传输层 Segment 如 TCP 段。强调由于数据太长,被拆分成了多个片段
网络层 Datagram 如 IP 包。强调这是一个完整的、具有路径选择信息的逻辑单元
数据链路层 Frame 如以太网帧。强调这是在物理线路上传输的一个个完整的电信号块

3. 封装过程

封装是数据从应用层物理层流动的过程。每一层协议栈都会在上一层交下来的数据前面加上自己的报头

第一步:应用层

产生用户数据(User Data)。如果应用程序有自己的协议(如 HTTP),则加上应用层首部(Appl Header)

第二步:传输层

数据进入内核协议栈的 TCP/UDP 部分。加上 TCP 首部

此时的数据单元被称为 TCP 段。TCP 确保数据能找到对方机器上的正确程序

第三步:网络层

数据继续下交给 IP 协议。在 TCP 段前面加上 IP 首部

此时称为 IP 数据报。IP 首部最重要的信息是源 IP 和目的 IP,这决定了数据包的路由方向

第四步:数据链路层

IP 包进入以太网驱动程序

  • 首部 :加上 以太网首部14 字节),包含源/目的 MAC 地址

  • 尾部 :加上 以太网尾部4 字节),用于差错校验

这就是最终在网线上跑的 以太网帧


4. 分用过程

当一个以太网帧从网线进入网卡,分用过程就开始了。该过程的核心在于依据头部字段信息执行多级路由选择

(1) 链路层分用

以太网驱动程序首先接收到帧,剥离以太网首部。查看以太网首部中的帧类型字段

分流去向

  • 如果是 0x0800,说明载荷是 IP 数据报,丢给 IP 协议 处理

  • 如果是 0x0806,说明是地址解析请求,丢给 ARP

  • 如果是 0x8035,则丢给 RARP

物流中心的大门(驱动)打开,看一眼包裹外壳上的标志:是普通邮件(IP)、地址查询函(ARP)还是身份确认函(RARP)

(2) 网络层分用

IP 协议层接过包裹,剥离 IP 首部。查看 IP 首部中的协议字段

分流去向

  • 如果是 6,说明里面装的是 TCP

  • 如果是 17,说明里面装的是 UDP

  • 当然,也可能是 ICMP (ping 命令用的)或 IGMP(组播用的)

到了楼层分拣处,管理员拆开包裹看了一眼内层标签:这东西是要给 TCP 部门处理,还是给 UDP 部门处理?

(3) 传输层分用

TCP 或 UDP 协议层剥离自己的首部。查看首部中的目的端口号

分流去向

  • 如果是 80,交给 Web 服务器进程

  • 如果是 22,交给远程登录进程

最后快递员进了办公楼,根据房号(端口号)把信件投递到具体的办公室(应用程序)里

从图中我们可以看到,网络栈的结构像一棵倒长的树

  • 向下封装时,是从应用层的繁多分支汇聚到网卡这一个主干发出去

  • 向上分用 时,是从网卡这一个入口进来,根据报头信息不断分流,最终准确地送达到成千上万个进程中的某一个

这就是为什么报头必不可少:如果没有报头里的这些 "类型" 和 "端口",内核面对原始二进制数据时将无从判断该将其交由哪个处理程序

四、跨网络通信

局域网通信如同教室点名,而跨网络通信则好比城市间快递寄送。此时仅靠 MAC 地址(类似身份证号)已不足够,必须借助更完善的寻址导航系统


1. 为什么需要 IP 地址

想象一下,如果你要给一个住在纽约的朋友寄信,你只在信封上写他的身份证号(MAC 地址),邮局(路由器)能送到吗?显然不能

  • MAC 地址的局限性:它只在当前局域网(同一网段)内有效。一旦超出该范围,物理地址将无法被识别

  • IP 地址的必要性 :我们需要一个能够体现地理位置网络拓扑结构的逻辑地址。IP 地址的作用是告诉网络设备:目标主机位于哪个远程子网中


2. IP 地址

在跨网络传输过程中,每经过一个路由器,MAC 地址都会被替换,但目的 IP 地址始终保持不变。IP地址就像导航指南,指引沿途所有网络设备将数据包准确送达目标逻辑网段的指定主机。若没有IP地址,互联网将退化为相互隔离的局域网,无法实现全球互联

如何查看 IP 地址?

作为开发者,查看 IP 是基本功。不同系统的命令有所区别:

  • Linux/macOS

    • ip addr:这是现代 Linux 系统(iproute2 工具包)推荐的命令,信息最全

    • ifconfig:传统的网络配置查看工具(需要安装 net-tools)

  • Windows

    • ipconfig:在 CMD 或 PowerShell 中输入即可

在 Linux 系统中查看网络信息时,IPv4 地址通常显示为 inet 后的数字(如 192.168.1.5)。而 lo(loopback)接口对应的 127.0.0.1 是本地回环地址,专门用于本机进程间的通信

IPv4 与 IPv6

目前互联网正处于从 IPv4 向 IPv6 过渡的长跑阶段:

  • IPv4:长度 32 位(4 字节),通常写成点分十进制,如 192.168.0.1。总量约 43 亿个地址。听起来很多,但面对全球百亿级的智能设备,早已分发殆尽

  • IPv6 :长度128 位(16 字节),采用十六进制表示,如 240e:3b3:2a01...。总量号称可以为地球上的每一粒沙子都分配一个独立的 IP 地址。它彻底解决了地址荒,并自带更高的安全性和传输效率

为什么 IPv6 难推广?

尽管IPv4地址资源已耗尽,但全面过渡到 IPv6 仍面临多重现实挑战:

  1. NAT:工程师们发明了 NAT 技术,让一个公网 IP 可以带着几百台局域网设备上网。这极大地缓解了 IPv4 的枯竭压力,导致大家觉得 "还能凑合过",动力不足

  2. 不向下兼容 : IPv6 是一套全新的协议,它和 IPv4 不兼容 。这意味着如果你的设备只支持 IPv6,你可能连不上只支持 IPv4 的老旧服务器。为了过渡,设备必须运行双栈,增加了技术复杂度

  3. 升级成本 : 全球数以亿计的路由器、交换机、防火墙以及各种古老的嵌入式设备,都需要升级固件甚至更换硬件才能支持 IPv6。对于运营商和企业来说,这是一笔天文数字般的开支

  4. 对普通用户来说,IPv4 也能刷视频、打游戏,IPv6 并没有带来某种 "非它不可" 的体验升级


3. 路由转发

在数据包跨越不同网络(经过多个路由器)的过程中:

  • 目的 IP 地址: 始终保持不变。它代表了包裹最终要送达的终点

  • 目的 MAC 地址: 在每一跳都会发生改变。它代表了包裹在当前局部路径下,下一站要交给谁

详细转发流程解析

假设主机 A(在上海局域网)要给主机 B(在伦敦局域网)发送一个数据包,中间经过路由器 R1 和 R2

第一步:主机 A 发出

主机 A 发现目标 IP 不在自己的局域网内,于是它决定把包交给 "默认网关"(路由器 R1)

  • 封装报文:

    • 源 IP / 目的 IP: A 的 IP / B 的 IP

    • 源 MAC / 目的 MAC: A 的 MAC / R1 的 MAC

  • 发送: 数据包通过物理线缆抵达 R1

第二步:路由器 R1 处理(第一跳)

R1 收到帧后,发现 "目的 MAC" 是自己,于是解包以太网头

  1. 拆解: R1 看到里面的 IP 头,发现目的 IP 是主机 B

  2. 查路由表: R1 查找路由表,发现要到达主机 B,下一站应该交给路由器 R2

  3. 重新封装: R1 会对数据包进行重新封装,为其更换新的以太网帧头

    • 源 MAC: 变为 R1 的出口 MAC

    • 目的 MAC: 变为 R2 的入口 MAC

    • IP 地址: 依然是 A 的 IP / B 的 IP

第三步:路由器 R2 处理(第二跳)

R2 重复 R1 的动作:

  1. 拆解: 剥掉 R1 封的 MAC 头,看 IP 头

  2. 查表: 发现目的 IP 就在自己直接连接的局域网里

  3. 重新封装:

    • 源 MAC: 变为 R2 的出口 MAC

    • 目的 MAC: 变为 最终目标主机 B 的 MAC

    • IP 地址: 还是 A 的 IP / B 的 IP

第四步:主机 B 签收

主机 B 收到帧,对比 MAC 地址一致,解包看到 IP 地址也一致,最后拆出载荷交给应用程序

MAC 地址到底是怎么改变的

你或许会感到好奇:路由器怎么知道下一跳的 MAC 地址是什么?

  1. 剥离: 路由器接收数据后,会把旧的、已经完成使命的链路层报头(包含旧的 MAC 信息)直接扔掉

  2. 决策: 路由器根据目标 IP 地址,决定数据包该从哪个网口发出去,以及下一跳是谁

  3. 查询: 路由器会通过 ARP协议向对应网口发送查询请求,询问下一跳 IP 地址对应的 MAC 地址

  4. **重组:**路由器在原始IP数据包前添加新的 MAC 头部


4. IP 与 MAC 的区别

IP 地址 MAC 地址
所属层级 网络层 数据链路层
唯一性 逻辑唯一。在同一网络中必须唯一,但可以动态更换 物理唯一。网卡出厂时烧录,全球唯一
表现形式 点分十进制(如 192.168.1.1) 十六进制(如 08:00:27:af:12:34)
传输变化 全程不变。指引数据包最终去往何方 逐跳更换。每经过一个路由器就换成下一站的地址
核心作用 远程导航。负责跨网段的路径规划 近场识别。负责在同一局域网内寻找目标
分配方式 由网络管理员配置或 DHCP 服务器动态分配 由硬件厂商预先分配

为什么要这么设计?

你可能会问:既然 IP 地址能找到目标,为什么还要 MAC?或者既然 MAC 全球唯一,为什么不能直接用它寻址?

1. 只有 MAC 地址行不行?

不行。 MAC 地址是平面的、无规律的。想象一下,全球有几十亿台设备,如果没有 IP 地址这种按 "省-市-区" 划分的层级结构,路由器就得存储几十亿条记录。这就像在没有任何行政区划的情况下,要在全世界找一个身份证号为 110xxx... 的人,这根本无从下手

2. 只有 IP 地址行不行?

也不行。 IP 地址只是逻辑位置,它最终需要落脚到物理硬件上

  • 在以太网中,网卡只认 MAC 地址

  • 如果没有 MAC 地址,当你把数据发到局域网时,所有网卡都无法通过硬件电路快速判断这个包是不是给自己的,只能全部交给 CPU 处理,网络效率会极其低下


5. IP 层屏蔽底层差异

在现实世界中,底层的物理链路是极其复杂的:有的是电缆组成的以太网 ,有的是空气传输的 WiFi ,有的是深埋海底的光纤 ,甚至还有古老的令牌环网

这些底层硬件的帧格式、最大传输长度、寻址方式各不相同。但奇妙的是,作为程序员,我们写代码时只需要关心对方的 IP 地址,完全不需要知道数据是通过光纤还是卫星传过去的

这就是 IP 协议(网络层) 的功劳------它提供了统一的网络抽象

(1) 现实类比

在没有集装箱之前,码头工人需要处理散装的木桶、麻袋、木箱,每种货物装上火车或轮船的方式都不一样,效率极低

  • IP 数据报就是集装箱 :无论里面装的是 HTTP 网页还是 QQ 消息,也无论外面是用卡车运还是轮船运(底层链路),集装箱的大小和规格(IP 报文格式)是全球统一的

  • 有了这层抽象,起重机(路由器)只需要识别集装箱上的编号(IP 地址),而不需要关心集装箱里面是什么,也不需要关心它是怎么被制造出来的

(2) Linux 的 "一切皆文件"

对于 Linux 开发者来说,这种 "屏蔽差异" 的思想再熟悉不过了

  • VFS (虚拟文件系统):在 Linux 中,你可能在使用 SSD、U 盘、甚至是网络存储。它们的底层驱动完全不同,但 Linux 通过 VFS 提供了一套统一的接口:open, read, write

  • IP 层就是网络的 VFS :底层网卡驱动千差万别,但内核协议栈在 IP 层将它们统一标准化。向上层提供了一个一致的视角:我只管把这个 IP 数据包交给下一跳,具体细节交由驱动处理

(3) 核心逻辑

IP 层主要通过以下三个关键机制实现其功能:

  1. 统一编址:不论你是手机、电脑还是路由器,只要接入互联网,就必须拥有一个逻辑上的 IP 地址,暂时抛弃复杂的 MAC 物理细节

  2. 统一封包格式 :所有的物理帧在进入 IP 层后,都会被解封装,提取出统一格式的 IP 数据报。在 IP 层看来,全世界的数据长得都一样

  3. 处理差异:如果底层的 WiFi 只能传 1500 字节,而光纤能传 4000 字节,IP 层会自动通过分片技术来适配这些物理差异,而不需要应用层程序员关心

IP 协议的设计体现了计算机科学中最核心的智慧:通过增加一个抽象层,可以解决绝大多数复杂性问题

总结

综上所述,从局域网通信、MAC 地址,到 IP 地址、封装与分用,再到跨网络路由转发,我们已经逐步梳理清楚了网络数据在协议栈中的基本流动过程

其中,MAC 地址负责局域网内的设备定位,IP 地址负责跨网络寻址,而 TCP/IP 协议栈则通过层层封装与解包,将复杂的网络通信拆分为多个职责清晰的模块共同协作完成

至此,我们已经能够站在协议栈视角,大致理解一条消息是如何从一台主机发送到另一台主机的。但进一步思考会发现:

应用程序究竟是如何接入TCP/IP协议栈,并真正向网络发送数据的?

这正是 Socket 编程要解决的问题

在下一篇中,我们将正式进入 Socket 编程预备阶段,开始认识网络字节序、端口号、socket 地址结构以及网络 API 的基本组织方式,为后续真正实现网络通信程序打下基础

相关推荐
TechWayfarer1 小时前
网络安全视角:利用IP定位API接口识别机房与基站流量(合规风控篇)
开发语言·网络·数据库·python·安全·网络安全
前端若水1 小时前
智能体开发与传统软件开发的核心区别
网络·人工智能·python·开源·log4j
tzy2331 小时前
Modbus:工业通信的“通用语言”
网络·串口·协议·modbus·rs-485·规约·iec 101
怀旧,1 小时前
【Linux网络编程】15. Reactor 反应堆模式
linux·网络·php
Kiyra1 小时前
【无标题】
网络
jiayong231 小时前
Memory 写入、检索与纠错机制:让 Agent 记住,也让它忘对
java·服务器·网络·hermes
小赵不会秃头2 小时前
数据结构Day 06:线性结构、库操作及 Makefile 完整学习笔记
java·linux·数据结构·算法·面试
雨田大大2 小时前
Windows11下IDEA运行后端时,端口被占用的解决方法
linux·运维·服务器
IKun-bug2 小时前
CentOS 7 安装 Claude Code 指南
linux·运维·centos