从物理层到CSMA/CD:以太网通信原理与故障排查
简介面向网络初学者、嵌入式开发者以及需要复习网络基础的人群这份物理层讲解文档从数据封装与解封装入手串联电路交换、报文交换和分组交换的差异帮助读者理解应用层数据如何逐层加上报头并经网卡与传输介质变为比特流。压缩包内共1个docx文件约3.46MB以图文讲解方式组织适合按章节阅读和整理笔记。内容结合快递包裹类比说明封装过程并展开同轴电缆、双绞线、光纤等传输介质以及10BASE5、共享型网络、冲突域、CSMA/CD载波侦听与退避重发等以太网基础概念同时说明分组交换通过分片、报头标识和固定传输大小提升链路复用效率并提到最小网络所需的网线、网卡与TCP/IP协议栈三要素。已有106人学习可作为课程补充、实验预习或面试前查漏补缺的材料帮助建立较完整的物理层知识框架。1. 物理层为什么“只传 0 和 1”的一层反而最难排查很多人学网络基础是从 TCP/IP 四层模型开始背的物理层永远排在最后像是“剩下的都归它管”的垃圾桶。可真到了设备现场Ethernet 链路起不来、ping 时通时断、抓包一片空白才会发现物理层是整个协议栈里唯一不提供补救机会的一层。上三层都在做逻辑上的补救——重传、校验、拥塞控制、超时重发——而物理层如果没把比特按正确的幅度、时序和编码规则送到对端上面所有机制都只是在错误的输入上做无谓的运算。抓包软件看不到任何帧不是因为它坏了而是因为帧根本没被正确识别出来。理解物理层本质上是理解“可靠通信的假设是从哪一刻开始成立的”。2. 三种交换方式分组交换为什么赢代价又落在谁身上2.1 电路交换先占一条线独占到底电路交换的核心动作发生在通信之前源端发出信令沿途每个节点为这条连接预留一段固定资源一个时隙、一段频段、一个端口整条路径逐跳建立完成之后数据才开始流动。这条通路一旦建成就是端到端独占的别人的数据进不来你的数据也不会被别人挤掉。这种设计带来两个直接后果。第一传输阶段几乎没有排队——路径固定、资源预留数据只需要承担传播时延时延抖动极小这正是语音业务最看重的性质。第二资源在整个会话期间被锁死哪怕你一句话不说那段带宽也空占着。人说话时大约有 40% 到 60% 是静默这部分容量在电路交换里就是纯浪费。除此之外建链需要额外时间中途任何一个节点故障整条连接直接断掉没有绕路的余地。2.2 报文交换用标识取代独占报文交换把“独占”换成了“排队”。发送方把整段数据作为一个报文交给第一个节点节点先完整收下来校验无误后查表决定下一跳再发出去——这就是存储转发。报文头部携带目的地址所以同一条链路可以被多个报文分时复用谁先到谁先走。省掉了建链过程链路利用率立刻上来了。但新的问题也很直接报文长度没有上限。一个几十兆的报文占着链路发后面等着的一串短报文全部被堵住这就是最原始的队头阻塞同时每个节点都必须准备足够大的缓冲区来装下最长报文成本压不下去最麻烦的是出错重传末尾一个比特翻了前面已经正确传输的部分全部要重来。2.3 分组交换把报文切成有上限的块分组交换在报文交换的基础上只加了一条约束单个数据块的长度必须有上限。发送前先把原始数据切成若干个不超过上限的分片每片加上头部头部里带源地址、目的地址和序号接收端按序号重组。这条“上限”是整个设计的支点它同时解决了四件事约束带来的效果机制解释单跳占用时间有界一个分组最长只占用链路L/R长度/速率时间后面的分组最多等这么久节点缓冲需求可控缓冲区按最大分组长度设计不随应用数据量增长重传粒度变小出错只重传一个分组不用重传整个报文流水线成为可能第 1 个分组在第 2 跳转发时第 2 个分组已经在第 1 跳发送流水线这一点最容易被低估。报文交换里整个报文必须完整到达节点才能转发分组交换里节点收到第一个分组就能立刻往下一跳送整条路径上同时有多个分组在“飞”。端到端吞吐不再受最慢一跳的完整传输时间限制而是接近瓶颈链路的速率。代价同样清晰。每个分组都要背一份头部开销按 IPv4 TCP 各 20 字节、数据段 1460 字节算头部占比约 2.7%链路层还有 14 字节帧头和 4 字节尾部校验。更要命的是排队分组到达是突发的出口速率固定队列长度随时在变于是时延抖动、乱序、丢包全都出现了。后面那些复杂的传输层机制——滑动窗口、拥塞控制、快速重传——本质上都是在给分组交换的这个副作用打补丁。2.4 不公平性从哪来统计复用没有预留题目正文里点出一个容易被忽略的现象数据大小不一致时转发会出现不公平。这个不公平不是实现缺陷而是统计复用的必然结果。链路带宽不做任何预留谁在这段时间内提交的分组多谁就占走更大比例的输出能力。一条大流量流可以把队列填满让交互式小流的分组排在后面时延从毫秒级涨到几百毫秒。我一般会这么理解“规定一个固定大小”这件事它的第一目的不是公平而是给单次占用时长封顶让排队时延有一个可计算的上界。真正的公平需要额外的调度器——加权公平队列按流分配权重令牌桶给每条流限速整形这些都是在分组交换之上再叠一层策略。物理层和链路层的长度上限MTU只保证“每个分组最多占用这么久”不保证“每条流拿到相同的份额”。把这两件事分开看很多网络行为的因果关系就顺了。提示分组长度上限是一个全局参数改小能降低排队时延、提升交互性但头部开销占比会上升吞吐下降。这个取舍在嵌入式场景里尤其明显小包高频的场景和批量传输场景的最优值并不相同。3. 封装与解封装从应用数据到线路上的比特流3.1 快递包裹模型每层只加自己关心的头封装的过程可以类比成寄快递。你把要送的小物件放进盒子快递点在外面套一层防水袋、贴一张面单中转站再加一张分拣标签最终运输车上看到的是贴着各种标签的包裹而收件人拆到最里面要的只是那个小物件。每一层只关心自己贴的那张标签不关心里面装了什么。对应到协议栈一次发送的完整结构是这样的[以太网头 14B][IP 头 20B][TCP 头 20B][应用数据 N B][以太网尾 FCS 4B] 目的MAC/源MAC 源IP/目的IP 源端口/目的端口链路层加的是 MAC 地址和帧校验负责“这一跳交给谁”网络层加的是 IP 地址负责“最终送到哪”传输层加的是端口号负责“交给哪个进程”。三个头部依次嵌套任何一层都不需要解析上层的负载内容。用代码把这个过程具象化会更清楚import struct def build_frame(payload: bytes, src_mac: bytes, dst_mac: bytes, src_ip: bytes, dst_ip: bytes, src_port: int, dst_port: int) - bytes: # 传输层源端口 目的端口 序号 校验和占位共 20 字节 tcp_hdr struct.pack(!HHIIHHHH, src_port, dst_port, 1, 0, 5 12, 65535, 0, 0x0000) # 网络层版本IHL、总长度、标识、TTL64、协议号 6 表示 TCP total_len 20 len(tcp_hdr) len(payload) ip_hdr struct.pack(!BBHHHBBH4s4s, 0x45, 0, total_len, 0, 0, 64, 6, 0, src_ip, dst_ip) # 链路层目的 MAC 源 MAC 类型 0x0800 表示上层是 IPv4 eth_hdr dst_mac src_mac struct.pack(!H, 0x0800) frame eth_hdr ip_hdr tcp_hdr payload # 尾部 FCS 由网卡硬件计算并追加软件侧不重复计算 return framebuild_frame依次拼接三层头部最后返回的是交给网卡的字节串。几个参数值得说明0x45拆开看是版本 4 加首部长度 5单位 4 字节即 20 字节这两个字段被压在一个字节里5 12是 TCP 首部长度字段同样是 4 字节为单位struct.pack的!前缀表示网络字节序也就是大端。真实的协议栈不会这样一次性拼完而是让每层维护自己的缓冲区只在需要时把头部预留出来避免数据被反复拷贝。3.2 解封装逐层剥离与逐层校验接收方向是反过来的但多了一件事每一层都要校验且校验失败的处理方式不同。链路层收到比特流后先做帧同步找到前导码和帧起始符算出 FCS 比对不匹配直接丢弃上层毫不知情网络层检查版本、首部校验和、目的地址是否属于自己传输层检查端口有没有对应进程监听没有就回一个重置。这里有个关键的不对称性链路层的校验只覆盖“这一跳”任何一跳的中继设备都会重新生成新的帧头和 FCS原始帧的校验值不会端到端保留。所以链路上一切正常也不代表数据没被改坏——中间某个节点的内存错误可以被下一跳的 FCS 完全掩盖。端到端的完整性要靠传输层校验和而传输层校验和本身也只是 16 位反码求和强度有限。物理层在这个链条里做的事情最“笨”把帧的每一个字节按位展开按编码规则变成电平变化送上介质。它不看头部、不查地址、不判断内容只保证时序和电平符合规范。也正因为如此物理层的错误全部以“帧根本没被正确接收”的形式体现而不是以“收到了一个错误的帧”的形式体现。3.3 最小网络三要素网线、网卡、协议栈把任何两台设备连成一个能通信的最小系统缺一不可的是三样东西。传输介质负责把信号从一端送到另一端网线、光纤、空气都算网卡负责数字域和模拟域之间的转换把并行的字节变成串行的比特流做编码、做 CRC、做电气隔离协议栈负责解释这些比特的含义决定发什么、什么时候发、收到之后交给谁。这三者的分工在今天的硬件上已经被高度整合。绝大多数网络芯片把 MAC 和 PHY 集成在一起协议栈也固化进芯片或操作系统内核买来的设备只要能联网基本都自带完整的 TCP/IP 实现。这种整合省掉了开发者大量工作但也带来一个副作用物理层变成了彻底的黑匣子出问题时你既看不到电平也看不到编码过程只能从上层现象倒推。理解三要素的边界就是知道该在哪一层去找证据。4. 冲突域与 CSMA/CD共享介质上的规则4.1 同轴电缆与 10BASE5一根线承载所有设备早期的以太网用同轴电缆组网一根粗缆贯穿整个楼层每台设备通过一个耦合器“刺”进这根缆的护套直接接触到内导体。所有设备共享同一段导体任何一个时刻发出的信号都会沿着缆向两个方向传播被所有设备听到。这就是共享型网络的物理基础。以太网标准的命名方式把关键参数都编码进去了以 10BASE5 为例10表示每秒 10 兆比特BASE表示基带传输即整个频带只传一路数字信号编码方式为曼彻斯特编码5表示单段最大传输距离 500 米。曼彻斯特编码的特点是每个比特周期中间必有一次电平跳变接收方可以直接从跳变中提取时钟不需要额外的时钟线——这在一条共享的总线上非常重要因为所有设备必须严格同步才能正确采样。共享型网络的问题在设备数量增加后迅速暴露。所有设备抢同一根线同一时刻只能有一台在发其余全在等信号在线上传播有延迟两端设备可能同时判断“线是空闲的”然后一起发缆上任何一处断了整个网段瘫痪。这根缆还很贵接头工艺要求高安装和维护都是一笔不小的开销。4.2 CSMA/CD先听后发、边听边发、冲突停发、随机重发冲突无法通过协议彻底消除只能被检测和化解。CSMA/CD 就是这套化解规则四个动作依次进行。先听后发。设备在发送前先监听介质上有没有电压摆动。如果线是安静的说明当前没有人在发可以开始。这一步依赖物理层的载波侦听电路响应时间必须足够快否则等它判断完别人已经发了。边听边发。发送过程中持续监听因为冲突可能在发送中途才发生——信号传播需要时间两台相距较远的设备完全可能在不同时刻各自判断“线空闲”。发送方必须能把自己的发送信号和收到的信号做比较一旦发现不一致就说明有别人在同时发。冲突停发。检测到冲突立刻停止发送转而发送一段强化冲突的干扰信号长度足够让总线上所有设备都感知到这次冲突避免有设备因为信号衰减而漏检。随机延迟后重发。这是整套机制里最关键的一步。如果所有冲突方都等同一个固定时间再发它们会再次同时发送冲突永远无法收敛。所以每台设备从[0, 2^n - 1]中随机取一个整数k等待k个时间片后再试n是这条帧已经经历的冲突次数封顶到 10重试 16 次仍失败则丢弃并上报。冲突次数越多可选窗口越大退避时间越长网络负载高时自动降低发送频率。这个策略叫二进制指数退避。import random def backoff(attempt: int, slot_time: float, max_attempt: int 16): attempt: 当前是第几次冲突从 1 开始 if attempt max_attempt: return None # 放弃向上层报错 n min(attempt, 10) # 窗口指数封顶在 2^10 k random.randint(0, (1 n) - 1) # 从 [0, 2^n - 1] 中取随机数 return k * slot_time # 实际等待时间slot_time是以太网的时间单位10 兆速率下等于 512 比特时间也就是 51.2 微秒。min(attempt, 10)这一行是收敛性的保证如果不封顶冲突次数一多窗口会指数膨胀到不可接受的程度网络恢复时间被拉得过长。封顶之后高负载下退避窗口固定在 1024 个时间片最坏等待时间可控。4.3 最小帧为什么是 64 字节冲突检测的时间窗口以太网规定最小帧长 64 字节这个数字不是随手定的它直接由冲突检测的物理约束推出来。设想最坏情况A 在缆的一端B 在另一端两者相距最远。A 开始发送信号需要一段时间才能传到 B。如果 B 在 A 的信号到达之前刚好判断线空闲并开始发送冲突就发生了。这个冲突信号要传回 AA 才能检测到。所以 A 从开始发送到收到冲突信号最长需要等一个往返传播时延。问题在于如果 A 发送的帧太短在冲突信号回来之前就已经发完了A 会认为这次发送成功根本不知道发生过冲突也不会重传。这一帧就彻底丢了而且没人负责。于是约束变成最小帧的发送时间必须大于等于两倍的最大单向传播时延。10 兆速率下512 比特的发送时间是 51.2 微秒对应往返传播时延上限 51.2 微秒扣除中继器引入的延迟后网络最大直径约 2500 米正好是五段 500 米粗缆通过中继器串起来的长度其中只有三段可以接设备。速率提升到 100 兆时同样的 512 比特只需要 5.12 微秒网络直径必须缩小到 200 米左右——这就是为什么高速以太网不能简单地把线拉长。注意这条约束意味着“短帧加长距离”是一个组合禁区。现场如果出现大量小于 64 字节的残帧runts计数增长除了怀疑线缆质量也要检查网段直径是否超出了当前速率允许的范围。4.4 双绞线与光纤冲突域是如何被缩小的双绞线取代同轴表面上是换了种线实质上是把“一条总线”变成了“一条点对点链路”。每台设备用一根独立的线连到中心设备物理上不再共享导体冲突只可能发生在中心设备内部。用集线器时中心设备把收到的信号向所有其他端口广播逻辑上仍然是共享介质仍然是半双工冲突域只是被集中到了一处规模反而更容易失控。交换机改变了这件事。它内部维护一张 MAC 地址表收到帧后只从目标端口转发出去每个端口各自构成一个独立的冲突域而且支持全双工——发送和接收各用一对线同时进行根本不存在争抢。冲突检测失去了存在意义CSMA/CD 在实际网络中逐步退场只在半双工配置下保留。光纤把这条路走到了终点。点对点、全双工、不受电磁干扰、传输距离以公里计冲突域这个概念在光纤链路上彻底消失。代价是成本和工艺光纤不能随便弯折接头需要熔接或冷接端面污染会造成衰减这些都属于物理层的“手艺活”。双绞线这边类别决定了能跑多快。Cat5 支持百兆Cat5e 在串扰指标上做了改进也常用于千兆Cat6 增加了十字骨架隔离四对线Cat6a 支持更宽频带。千兆速率下八根线全部投入工作四对线同时双向传输每对承担 250 兆靠回声消除技术把发送信号从接收信号里减掉从而实现同一对线上的全双工。百兆只需要两对——一对发、一对收另外四根空闲。这个差异在现场排查时非常有用后文会再提到。5. 排查物理层那些“玄学”故障的定位路径5.1 五条踩坑记录现象一链路显示 up速率协商成百兆怎么都上不去千兆。原因通常在线序上。千兆需要四对线全部参与如果水晶头只压了 1、2、3、6 四根或者 4、5、7、8 接触不良自协商会退回到只需两对的百兆模式链路照样 up误码计数也正常只有速率不对。解决方式是先用测线仪逐芯测通断再确认两端水晶头都按同一线序压接最后看接口协商结果里的速率和双工字段。现象二小流量一切正常一跑大流量就丢包延迟飙高。大概率是双工不匹配。一端被手工强制成全双工另一端还在自协商自协商机制被破坏后对端只能退回半双工。半双工那一端会做载波侦听和冲突退避而全双工那一端不管不顾地发结果就是大量冲突和丢弃。证据是接口计数器里的冲突计数和晚冲突计数持续增长。解决方式是两端统一要么都开自协商要么都手工强制成相同的速率和双工。现象三链路偶发中断CRC 错误计数缓慢上涨。这类问题最像玄学因为它是渐进式的。常见原因是线缆长度超过 100 米、线缆走过强电区域、水晶头氧化、或者用了铜包铝的劣质线。信号衰减和近端串扰会让某些比特在采样时判错FCS 校验失败帧被丢弃上层表现为零星重传。解决方式是缩短距离、换屏蔽或更高类别的线、避开动力电缆然后用误码计数验证是否归零。现象四光纤链路起不来或者起来了但光功率偏低。两个高频错误单模和多模混用以及收发没有交叉。单模纤芯直径约 9 微米多模是 50 或 62.5 微米两端模块类型必须一致否则耦合损耗巨大。收发方面本端的发送必须接到对端的接收同一对纤不能 TX 对 TX。排查工具是光功率计先测发送功率再测接收功率对比模块的灵敏度指标能快速区分是模块坏了还是接错了。现象五老同轴网段冲突率异常高小包大量丢失。同轴总线两端必须各接一个 50 欧姆终端电阻用来吸收到达端点的信号能量。少接一个信号在端点反射回来和原始信号叠加形成驻波接收方采样到的波形严重畸变。解决方式很朴素检查两端终端电阻是否在位、阻值是否正确中间任何一段缆断开都会让整个网段失效。5.2 从现象反推层级先看计数器再看协议物理层故障的排查顺序应该反过来不要从协议开始抓包先从接口计数器开始看。现象优先看的证据常见指向链路 down光功率、协商结果、线序介质或模块链路 up 但速率不对协商速率、双工字段线序缺芯、自协商被关零星丢包、延迟抖动CRC 错误、runts、冲突计数线缆质量、双工不匹配完全收不到帧收发是否交叉、VLAN 与端口状态物理连接或配置这套顺序的价值在于成本看计数器只需要一条命令换线缆要停机抓包要复现。先把范围压到物理层再去怀疑协议栈能省掉大量无效排查。6. 设计取舍把复杂度放在哪一层物理层的所有设计本质上是同一个问题的不同答案复杂度该放在哪里。以太网选择了“简单网络、智能终端”。物理层只承诺尽力把比特送出去不承诺送达、不承诺顺序、不承诺不重复正确性交给上层的校验和重传。这个选择让物理层可以极度简化——不维护状态、不建连接、不做确认任何一段介质坏了只影响局部换掉就行。代价是端系统必须承担全部可靠性工作协议栈变复杂头部开销变大重传带来额外延迟。分组交换选择了“牺牲确定性换利用率”。电路交换能给出确定的时延上界代价是静默期浪费带宽分组交换把带宽利用率推到接近饱和代价是排队时延不可预测、需要拥塞控制来防止崩溃。今天几乎所有数据网络都选后者因为绝大多数应用能容忍抖动却无法容忍带宽浪费。硬件卸载则是在“谁来算”上做取舍。CRC 计算、校验和验证、帧的收发搬运全部下沉到网卡CPU 只处理有效载荷。嵌入式设备里这个取舍更极端协议栈直接固化在芯片里开发者调用几个接口就能收发数据换来的是对底层行为的不可见。想调一个重传超时、想看一次冲突退避往往发现根本没有这个旋钮。我踩过一次印象很深的坑某台设备批量传输时吞吐只有预期的一半抓包看一切正常应用层没有任何异常日志干净得像新装的。查了两天才发现是网线只压了四根链路一直跑在百兆而所有上层指标都是健康的——没有任何报错只是慢。从那以后我每次接手一个网络问题都强制先走一遍物理层看协商速率、看双工、看 CRC 和冲突计数、看线序把这一层排除干净再往上查。这个习惯至少帮我省掉了一半的排查时间。这份资料把交换方式、封装解封装、传输介质、以太网标准和 CSMA/CD 这几块串成了一条完整的线从“数据怎么被切成块”一直讲到“块怎么变成线上的电平”中间没有跳跃。想要把网络基础的底层逻辑一次理顺可以顺着这份文档把物理层这一段彻底过一遍后面再看 IP 和 TCP 的很多设计会突然变得理所当然。希望帮到你。本文还有配套的精品资源点击获取