计算机网络这门课的笔记,我前后推翻重做过三次。第一次是照着课件逐页抄,抄完发现脑子里只剩下一堆缩写;第二次改成画图,五层模型画得挺好看,一遇到拥塞窗口的计算题还是卡壳;第三次我才想明白,这门课的笔记不能按“章节”来组织,得按“一条数据从发出到被接收”的路径来组织,再把手算题、抓包实验、协议状态三者绑在一起记。这套方法后来被我用到不止一门课上,也算意外收获。下面这份内容,就是我把一整套计算机网络课程笔记从零搭起来、再反复修补后的完整复盘,包含知识体系怎么切、核心协议怎么算、实验怎么补、坑在哪。适合正在学这门课的同学、准备面试复习的人,以及任何想把自己脑子里那套“协议栈”重新捋一遍的人。全文里出现的具体环境、项目都做了模糊处理,不影响方法本身的通用性。
1. 笔记体系怎么搭才不塌:先定骨架再填肉
1.1 这门课真正的难点不在概念,而在“看不见”
计算机网络最劝退的地方,是它讲的几乎所有东西都发生在你眼睛看不到的地方。数据链路层的帧长什么样、TCP 的窗口怎么滑动、路由表怎么收敛,这些既没有画面也没有手感,全靠脑补。我第一遍学的时候,把“三次握手”背得滚瓜烂熟,可一旦被问到“如果第二个报文丢了会发生什么”,立刻就哑了。原因很简单:我记住的是结论,不是过程。
所以我后来定了一条原则:笔记里凡是涉及“过程”的知识点,必须能画出至少一条时间轴;凡是涉及“数值”的知识点,必须能代入一组具体数字算出来。画不出时间轴,说明我没真懂;算不出数字,说明我只是认得公式。这条原则执行下来,笔记的厚度翻了将近一倍,但复习效率提升了不止一倍,因为笔记从“名词解释手册”变成了“过程推演手册”。
这里补一句经验:不要一上来就追求笔记好看。我见过太多人把时间全花在排版和配色上,结果知识一条没进脑子。前两周的笔记丑一点没关系,等到知识结构稳定了再统一整理,返工成本反而低。
1.2 我最后定下来的六块目录结构
整套笔记我按六个大块切分,顺序不完全等同于教材,而是按“从抽象到具体、从上到下”的逻辑排:
| 序号 | 模块名称 | 核心内容 | 笔记里的呈现形式 |
|---|---|---|---|
| 1 | 分层与性能 | 五层模型、封装解封装、四类时延、带宽时延积 | 一张手绘封装图 + 一张公式卡片 |
| 2 | 应用层 | HTTP、DNS、邮件协议、CDN 基本思路 | 抓包截图 + 请求响应解析 |
| 3 | 传输层 | UDP、TCP 状态机、滑动窗口、拥塞控制 | 状态迁移表 + 手算曲线 |
| 4 | 网络层 | IP 编址、子网划分、路由算法、NAT | 计算题模板 + 路由收敛表 |
| 5 | 链路层 | 差错检测、CSMA/CD、以太网帧、交换机 | 帧结构图 + 自学习推演 |
| 6 | 实验与排错 | 抓包分析、套接字编程、仿真拓扑 | 可复现的操作记录 |
这个结构的价值在于,它天然对应了“一层负责一件事”的思维方式。后面做题、做实验、被追问,我只要先定位到层,再顺着这一层的职责去想,基本不会跑偏。比如被问“为什么网页打开慢”,我会从应用层(DNS 解析、HTTP 请求数)往下排查,而不是一上来就怀疑网卡坏了。
注意:不要把这六块当成六个孤立的抽屉。任何一次真实的通信都会穿过全部六块,笔记里每一块的开头我都留了一行“这一层从哪里接过数据、又交给谁”,强行把上下文接上。
1.3 工具链取舍:手写、笔记软件、抓包工具各干什么
工具这块我试过不少组合,最后固定为三件套,各司其职。
手写(或平板手绘)负责过程类内容。状态机、时间轴、封装层级图、路由收敛过程,这些必须手画,因为画的过程本身就是理解的过程。我用打印出来的空白状态图,逼自己每个箭头旁边写触发条件和报文类型,写不出来就说明没掌握。
笔记软件负责结构化检索。我用的是支持双链的本地笔记软件,核心诉求只有两个:一是能用标签把跨章节的同一概念串起来(比如所有涉及“重传”的位置都打同一个标签),二是能全文搜索。选型逻辑很简单:这门课的复习高度依赖“顺着一个概念把所有相关点捞出来”,双链和标签能做到,纯文件夹结构做不到。
抓包工具负责把抽象变具体。它是我整个笔记体系里最重要的一环,因为它是唯一能让你“看见”协议的东西。每一次握手、每一个窗口更新、每一次重传,都能在抓包里找到对应的一帧。关于具体怎么用,第 5 节展开。
顺手提一句选型心得:不要因为工具高级就去用它。我一度想用网络仿真做所有实验,结果一个拓扑配了两小时还没通,学习热情直接浇灭。后来改成“小实验用抓包、需要多节点才上仿真”,节奏才稳住。
2. 分层模型怎么记才不散架:只记每一层加了什么
2.1 五层与七层的映射,别死背对应表
教材里那套七层模型和实际在用的五层模型,很多人是靠背对应关系过关的,我一开始也这么干,结果考完就忘。后来我换了个记法:不去记“谁对应谁”,而是记“每一层往数据前面加了什么,为什么要加”。
应用层不加密任何头部,它就是数据本身,因为这一层只关心“我要说什么”。传输层加的是端口号,解决“哪个进程收发”的问题;同时带上序号和确认号,解决“可靠不可靠”的问题。网络层加的是 IP 地址,解决“跨网络怎么找到目标主机”。链路层加的是 MAC 地址和帧校验,解决“同一段链路上下一跳给谁、传坏了怎么发现”。物理层什么头都不加,只负责把比特变成信号。
这么记的好处是,每一层的头部字段都能反推出它的职责。被问到“为什么网络层不需要端口号”,答案自然就出来了:网络层只负责把包送到目标主机,送到之后交给哪个进程是传输层的事。这比背一张对应表扎实得多。
2.2 封装与解封装:用一条主线串起全部章节
我在笔记的第一页贴了一张自己画的图,画的是一次网页访问的完整路径:浏览器发起请求 → 传输层分段加端口 → 网络层加 IP 头 → 链路层加帧头帧尾 → 网卡发出 → 经过若干跳路由器(每跳都解封装到网络层再重新封装链路层)→ 到达目标主机逐层上交 → 服务端处理并回送。这张图画了三遍才顺,但画完之后,整本书的章节在我脑子里就自动排好队了。
这里有个容易忽略的细节值得单独记:路由器在转发时,链路层的帧头帧尾是每跳都换的,但 IP 头基本不变(除了 TTL 递减和校验和重算)。这个点在选择题和面试里出现频率极高。我在笔记里专门用红笔标注:“MAC 地址是段内地址,IP 地址是端到端地址”。理解这一句,很多关于“地址会不会变”的困惑就一次性解决了。
2.3 时延计算:把公式做成可代入的模板
四类时延:发送时延、传播时延、处理时延、排队时延。前两个必须会算,后两个一般只做定性分析。我把它们做成了一张模板卡,每次做题直接套:
- 发送时延 = 数据长度 ÷ 带宽
- 传播时延 = 链路长度 ÷ 信号传播速度(铜缆和光纤通常按 2×10⁸ m/s 量级估算)
- 总时延(停等协议下,忽略处理和排队)= 发送时延 + 2 × 传播时延
举个我笔记里留的例题:链路带宽 100 Mbps,单向传播时延 10 ms,要发送一个 1 MB 的文件。发送时延 = 1×2²⁰×8 bit ÷ 100×10⁶ bit/s ≈ 83.9 ms;往返传播时延 = 20 ms;如果按停等协议一个一个发,总时间约为 103.9 ms。但如果文件大到需要分组,且窗口足够,总时间就趋近于“发送时延 + 一个往返”,这就是流水线带来的差别。
带宽时延积这个概念我当时没重视,后来吃了亏。它等于带宽 × 往返时延,代表“链路上一共能装下多少比特”。还用上面这组数字:100 Mbps × 20 ms = 2×10⁶ bit = 250 KB。这个数值直接决定了窗口要开多大才能填满链路,是后面理解滑动窗口和拥塞控制的基础。我在笔记里把它写成一行大字:窗口小于带宽时延积,链路就闲着。
3. 传输层笔记的核心:状态机、窗口、拥塞控制三件套
3.1 三次握手四次挥手:用状态迁移表替代背图
几乎所有人都能画出三次握手的箭头图,但真正被追问的时候,考的不是图,是状态。所以我把笔记里的图换成了表,每一行是“当前状态 + 收到什么报文 + 发送什么报文 + 转到什么状态”。
| 当前状态 | 收到 | 动作 | 转到 |
|---|---|---|---|
| CLOSED | 主动打开 | 发 SYN,seq=x | SYN_SENT |
| SYN_SENT | SYN+ACK | 发 ACK,seq=x+1,ack=y+1 | ESTABLISHED |
| LISTEN | SYN | 发 SYN+ACK,seq=y,ack=x+1 | SYN_RCVD |
| SYN_RCVD | ACK | 无 | ESTABLISHED |
| ESTABLISHED | 应用关闭 | 发 FIN,seq=u | FIN_WAIT_1 |
| FIN_WAIT_1 | ACK | 无 | FIN_WAIT_2 |
| FIN_WAIT_2 | FIN | 发 ACK | TIME_WAIT |
| TIME_WAIT | 等待 2MSL | 无 | CLOSED |
这张表比图有用得多,因为所有“异常情况”题都能顺着表推。比如“第二个报文丢失会怎样”:客户端停在 SYN_SENT,超时后重传 SYN,服务端可能已经收到了重复 SYN,于是重发 SYN+ACK。这类题的答案不在记忆里,在表里。
TIME_WAIT 等待 2MSL 这两个理由,我在笔记里写得很具体:一是保证最后一个 ACK 能到达对端(丢了的话对端会重发 FIN,本端还能再回一个 ACK);二是让本连接在网络中的残留报文自然消亡,避免干扰使用相同四元组的新连接。这两个理由写下来只要两行,但被问到的时候能直接答出,比含糊地说“为了保证可靠”强太多。
3.2 滑动窗口与流量控制:拿一组数字算一遍
流量控制这块,光看“窗口滑动”的动画是记不住的,必须自己算。我笔记里的标准流程是这样的:接收方通告窗口 rwnd,发送方最多发 rwnd 字节未确认数据;发送方自己的拥塞窗口 cwnd 与 rwnd 取较小值作为实际可发送量。
举个具体例子:接收方缓冲区 4000 字节,已收到 2000 字节,应用还没读走,那么它通告的窗口就是 2000。发送方已发送未确认 1500 字节,它还能再发 500 字节。这个推演我在笔记里做了五轮,每轮换一组数字,直到不用想就能算出来。
零窗口是个经典考点,我单独记了一条:接收方窗口为 0 时,发送方启动持续计时器,超时后发零窗口探测报文,接收方回应当前窗口值。如果不做这一步,双方就会死锁——发送方等窗口更新,接收方等数据,谁也不动。
窗口缩放这个点也值得记一笔。TCP 头部窗口字段只有 16 位,最大 65535 字节,在高带宽时延积链路上根本不够用(回想上一节算的 250 KB)。所以有窗口缩放选项,用移位的方式把窗口放大,最大可到 2³⁰ 字节量级。这个知识点在教材里常常一笔带过,但它是理解“为什么现代网络的 TCP 参数和课本不一样”的钥匙。
3.3 拥塞控制的四个阶段:手算 cwnd 变化曲线
这是全课最值得动手算的部分。我把慢启动、拥塞避免、快重传、快恢复四个阶段做成一张 cwnd 随往返次数变化的表,用最朴素的假设:初始 cwnd = 1 MSS,慢启动阈值 ssthresh = 16 MSS,无丢包。
| 往返次数 | 阶段 | cwnd(MSS) |
|---|---|---|
| 0 | 慢启动 | 1 |
| 1 | 慢启动 | 2 |
| 2 | 慢启动 | 4 |
| 3 | 慢启动 | 8 |
| 4 | 慢启动 | 16 |
| 5 | 拥塞避免 | 17 |
| 6 | 拥塞避免 | 18 |
| 7 | 拥塞避免 | 19 |
算完这张表,慢启动“指数增长”、拥塞避免“线性增长”就不再是两句空话。接着再加丢包场景:第 7 轮发生超时,ssthresh 变成当前 cwnd 的一半即 9.5 取整为 9,cwnd 回到 1,重新慢启动,涨到 9 之后转拥塞避免。如果第 7 轮收到三个重复确认,走的是快重传加快恢复:ssthresh 同样减半,cwnd 设为 ssthresh,直接进入拥塞避免。
我把这两种情况的曲线画在同一张坐标纸上,一条是“锯齿”,一条是“半锯齿”,对比非常直观。这一步做完,Reno 和 Tahoe 的区别根本不用背。
提示:手算时一定写清楚“每一轮”指的是一个往返时延,不是发一个报文。这是最常见的算错原因,我自己就因为这个把整道大题算反过。
3.4 UDP 与新兴传输方案在笔记里的位置
UDP 部分内容不多,但我在笔记里给它留了一整页,因为它是后面很多内容的对照物。UDP 只做多路复用和简单的差错检测,不保证可靠、不保证顺序、不做拥塞控制。正因为它“什么都不管”,所以它快、头部小、适合实时音视频和查询类请求。
我还在这一页补了一段延伸:现代很多基于 UDP 的传输方案,把可靠性、有序性、拥塞控制挪到应用层自己做,好处是可以按业务定制,比如对实时性敏感的流可以放弃重传、只做前向纠错。这段内容不在基础教材里,但它能把“为什么 UDP 没有被淘汰”这件事讲通,也能让你在面试里多一个可聊的角度。
写这部分的心得是:不要因为某个协议“简单”就跳过。简单的东西往往是对照组,理解了对照组,复杂协议的设计动机才立得住。
4. 网络层与链路层:计算题和转发逻辑的主战场
4.1 子网划分:三道模板题打通全部变体
子网划分是这门课性价比最高的得分点,因为题型固定、步骤固定。我在笔记里固化了三步:先确定要借几位,再算块大小,最后列出网络地址、可用范围和广播地址。
模板题一:把 192.168.10.0/24 划成 4 个等长子网。4 个子网需要借 2 位,前缀变成 /26,掩码 255.255.255.192,块大小 = 256 − 192 = 64。四个子网分别是 .0、.64、.128、.192,每个子网 64 个地址,可用主机 62 个。
模板题二:不等长划分。需求是 100、50、25、10 四段。按从大到小分配:100 台需要 /25(128 个地址),50 台需要 /26(64 个),25 台需要 /27(32 个),10 台需要 /28(16 个)。依次从 192.168.10.0/24 里切:/25 拿走 .0–.127,/26 拿走 .128–.191,/27 拿走 .192–.223,/28 拿走 .224–.239,还剩 .240–.255 可用。
模板题三:给一个地址和掩码,判断两个主机是否同子网。做法是把 IP 和掩码做按位与,比较结果是否相同。比如 172.16.5.33/27 和 172.16.5.62/27,掩码 255.255.255.224,块大小 32,前者落在 .32 段,后者落在 .32 段(.32–.63),同子网。换成 .65 就落到 .64 段了。
这三道题我各做了五遍,直到能在两分钟内写完一道。经验是:先算块大小,再找落点,不要一上来就写二进制。块大小是 256 减掩码最后一段,这个技巧能省掉大量时间,也最不容易出错。
4.2 路由算法:距离向量和链路状态的差别在哪
距离向量和链路状态这两套算法,教材讲得都很抽象,我用一句话概括记在笔记顶部:距离向量是“听邻居说”,链路状态是“自己看全局”。
距离向量的代表是 RIP,每个路由器只和邻居交换自己的整张路由表,收到后按“邻居距离 + 1”更新,跳数超过 15 视为不可达。它的毛病是收敛慢,会出现“坏消息传得慢”的问题。解决办法是水平分割(从哪个接口学来的路由不再从这个接口发回去)、毒性逆转(把从某接口学来的路由标记为不可达再发回去)、触发更新(拓扑一变立刻发,不等周期)。这三个机制我在笔记里画了三个小场景推演,每个场景只有三台路由器,画完就明白为什么需要它们。
链路状态的典型是 OSPF,每个路由器洪泛自己的链路状态通告,最终每台路由器都有一张完整的拓扑图,然后用最短路径算法自己算路由。它的好处是收敛快、不会出现计数到无穷,代价是要维护拓扑数据库,开销更大。
我把两者的对比做成一张表放在一起,复习时扫一眼就够:
| 维度 | 距离向量 | 链路状态 |
|---|---|---|
| 掌握的信息 | 只知道邻居告诉的距离 | 拥有全网拓扑 |
| 交换内容 | 整张路由表 | 自己的链路状态 |
| 收敛速度 | 慢,可能计数到无穷 | 快 |
| 典型问题 | 环路、坏消息传得慢 | 洪泛开销、区域划分复杂 |
| 应对手段 | 水平分割、毒性逆转、触发更新 | 分层区域、泛洪控制 |
4.3 ARP、DHCP、NAT 这三个“配角”必须单独记
这三个协议在教材里往往散落在不同章节,但它们在实际通信里是连在一起的,所以我单独开了一页,按“一次上网从零开始”的顺序记。
先是 DHCP,四步交互:发现、提供、请求、确认。客户端一开始没有地址,所以用广播发发现报文;服务端回应提供报文,带上可用地址和租期;客户端广播请求,明确选定某个服务端;服务端回确认,附带其他配置(网关、DNS)。这里有个细节值得记:请求阶段仍然用广播,是为了让其他也发过提供报文的服务端知道自己的提议没被选中,可以回收地址。
然后是 ARP,在同一个局域网内把 IP 地址解析成 MAC 地址。请求是广播,应答是单播。我在笔记里特别标注了一句:ARP 请求里的目标 MAC 是全 F 的广播地址,但应答是直接发给请求方的。另外还有免费 ARP,主机主动广播自己的 IP 与 MAC 映射,常用于地址冲突检测和网关切换后刷新缓存。
最后是 NAT,把内网地址在出口处转换。实际用得最多的是带端口映射的形态,用“内网 IP + 端口”和“公网 IP + 端口”建立映射表,靠端口区分不同内网主机。我记了一条实践观察:NAT 让端到端透明性被打破,所以后来才有了各种穿透方案。这句话在面试里被追问过,答得出来很加分。
4.4 链路层:帧长、争用期、交换机自学习
链路层两个必算的点:最小帧长和争用期。以太网取 64 字节作为最小帧长不是随便定的,它要保证发送方在帧发完之前能检测到冲突。10 Mbps 以太网下,争用期取 51.2 微秒,乘以带宽就是 512 bit,也就是 64 字节。换到 100 Mbps,争用期缩到 5.12 微秒,最小帧长仍然是 64 字节。这个推导我在笔记里写了三行,比记结论可靠。
交换机自学习也很好推:收到一帧,先把“源 MAC + 入端口”写进转发表,老化时间一般 300 秒;然后查目的 MAC,查到就单播转发,查不到就泛洪(除入端口外所有端口)。遇到目的端口和入端口相同,直接丢弃。这三个动作我画了一张三节点的推演图,跑了五轮,每轮换一个未知目的地址,跑完就彻底清楚了。
差错检测部分记两条就够:奇偶校验只能查一位错,检错能力弱;循环冗余校验用多项式除法,检错能力强,以太网帧尾用的就是它。CRC 只能检错不能纠错,纠错要靠重传,这个区分很多人搞混。
5. 笔记落到实操:抓包、套接字、仿真三件套
5.1 抓包工具的三个必做实验
抓包是我笔记里唯一“不能只靠看书”的部分。我固定做了三个实验,每个都对应一章的核心知识。
实验一:观察三次握手和四次挥手。过滤器写tcp.flags.syn == 1 && tcp.flags.ack == 0能精准捞出连接建立的第一个报文,再顺着看序号和确认号的变化。重点看两件事:序号是怎么递增的,以及谁先发 FIN。抓完对着状态迁移表逐帧核对,比看图有效十倍。
实验二:观察 HTTP 请求响应与 DNS 解析。用http.request.method == "GET"过滤请求,用dns过滤域名解析,看一次网页访问到底先发生什么、后发生什么,以及有没有复用连接。这一步能直观感受到应用层和传输层的配合。
实验三:观察重传与窗口更新。用tcp.analysis.retransmission可以直接把重传帧挑出来,再看看前后的 ACK 和窗口字段。有条件的可以人为制造丢包(比如临时断开再恢复),亲眼看一次快重传是怎么触发的。
注意:抓包前先确认你抓的是自己设备的流量,且只用于学习分析。抓到的报文里可能包含地址、Cookie 等信息,截图发出去前记得打码或裁剪,这个习惯越早养成越好。
常用过滤表达式我整理成了一张小抄贴在笔记里:
| 目的 | 过滤表达式 |
|---|---|
| 只看某个端口 | tcp.port == 8080 |
| 只看某台主机 | ip.addr == 192.168.1.10 |
| 只看握手首包 | tcp.flags.syn == 1 && tcp.flags.ack == 0 |
| 只看 DNS 查询 | dns.flags.response == 0 |
| 只看重传 | tcp.analysis.retransmission |
| 只看某域名 | dns.qry.name contains "example" |
5.2 用套接字写一遍协议,知识会立刻变实
光抓包还不够,自己写一遍才知道协议字段是怎么被填进去的。我用 Python 写了两个最小实现,一个 TCP 回声服务,一个 UDP 回声服务,代码不长,但把“服务端监听、客户端连接、收发、关闭”这条链路走通了。
import socket # TCP 回声服务端:先监听,再逐个处理连接 server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) server.bind(("127.0.0.1", 9000)) server.listen(5) while True: conn, addr = server.accept() data = conn.recv(1024) conn.sendall(b"echo: " + data) conn.close()import socket # TCP 客户端:连接后发送一次,读取一次回显 client = socket.socket(socket.AF_INET, socket.SOCK_STREAM) client.connect(("127.0.0.1", 9000)) client.sendall(b"hello") print(client.recv(1024)) client.close()写完之后我做了个实验:在客户端和服务端之间插一层抓包,看connect到底对应哪几个报文,close又对应哪几个。结果很直观——connect触发三次握手,close触发四次挥手。这一步做完,“套接字 API 是传输层协议的外壳”这句话才算真的理解。
UDP 版本更简单,服务端用recvfrom和sendto,客户端连connect都可以不要。对比两者代码,能明显感觉到“面向连接”和“无连接”在编程接口上的差别。
5.3 仿真拓扑:多节点实验的最小可行方案
单机抓包只能看到自己,要看路由、要看交换机转发,就得上仿真。我用的方案很轻:开源的轻量网络仿真工具,用几行命令拉起一个拓扑,用命令行在节点间做连通性测试和抓包。
# 拉起一个最简单的三节点线性拓扑并进入交互命令行 sudo mn --topo linear,3 --link tc进入之后可以用h1 ping h2测连通,用h2 tcpdump -i h2-eth0抓包,用links看链路状态。这类工具的好处是拓扑改起来快,想看广播域就加一台交换机,想看路由收敛就换成多台主机加路由器。我做过的最小实验是“两台主机跨一台路由器通信”,配完地址和路由之后,先 ping 通,再抓包看 ARP 和 ICMP 的顺序,最后故意写错网关地址,观察现象。
仿真这块我踩过一个坑:一开始配完地址就 ping,一直不通,排查了半小时才发现是路由表没写回程路由。单向能通不代表双向能通,这个教训我在笔记里用红笔写了一行:排连通性先查去、再查回。
5.4 把应用层协议也拉进实验里
很多人做实验只做到传输层就停了,其实应用层更贴近日常。我做过两个小实验,都很短但收获不小。
第一个是手动构造一次 HTTP 请求。用命令行工具连到某个测试服务,直接手打请求行和首部,看服务端回什么。这个过程能真切看到“请求行、首部、空行、实体”的结构,也能理解为什么首部末尾必须有一个空行。
第二个是观察 DNS 缓存。连续两次解析同一个域名,第一次耗时明显长,第二次几乎瞬间返回,这就是缓存生效。再用不同的域名测试,能直观看到递归查询和迭代查询的差别。
这两个实验加起来不到二十分钟,但把应用层那一章从“背协议名”变成了“我知道它长什么样”。
6. 常见问题与排查技巧实录
6.1 概念混淆速查表
这门课最容易混的就是几组“看起来差不多”的概念,我把它们整理成表,复习时扫一遍就行。
| 容易混的点 | 核心区别 | 一句话记忆 |
|---|---|---|
| 流量控制 vs 拥塞控制 | 前者管接收方来不及收,后者管网络来不及传 | 一个看对端,一个看全网 |
| 发送时延 vs 传播时延 | 前者与数据量和带宽有关,后者只与距离和介质有关 | 一个是“往外倒水”,一个是“水流过去” |
| MAC 地址 vs IP 地址 | 前者段内有效、逐跳改变,后者端到端、基本不变 | 一个像门牌号,一个像收件地址 |
| 交换机 vs 路由器 | 前者工作在链路层按 MAC 转发,后者在网络层按 IP 转发 | 一个管内,一个管外 |
| 检错 vs 纠错 | CRC 只能发现错误,纠正要靠重传 | 发现问题和解决问题是两回事 |
| 三次握手 vs 四次挥手 | 建立时服务端可把 ACK 与 SYN 合一,关闭时两个方向要分开 | 开可以合并,关必须分开 |
这张表我建议自己动手写一遍,写完再对照,记忆效果比直接抄好得多。
6.2 实验不通时的排查顺序
实验做不出来是常态,关键是别乱试。我总结了一套固定顺序,从下往上查:
- 先看链路有没有起来。接口是不是 up,有没有分配到地址。
- 再看同网段能不能通。同网段不通,问题多半在地址、掩码或链路本身。
- 然后看网关和回程路由。单向通、双向不通,十有八九是回程路由缺失。
- 接着看名字解析。用 IP 能通、用域名不通,问题就在解析环节。
- 最后看上层服务。端口有没有监听、防火墙有没有拦。
这个顺序的价值在于排除法:每往下走一步,就排除了上面所有层的可能。我见过不少人一上来就怀疑应用层,结果折腾半天发现是网线没插好。
6.3 笔记越记越乱的三条自救
第一条:同一概念只留一个主条目。我早期在四个地方写过“拥塞窗口”,内容还不一致,复习时自己都搞不清哪个是对的。后来改成一处写全,其他地方只放链接。
第二条:计算题模板和概念笔记分开存。概念笔记按章节组织,计算题模板单独一个文件,按题型组织(时延、窗口、子网、帧长、路由收敛)。做题时只翻模板文件,效率高很多。
第三条:每章末尾留一块空白,专门写“我错过的题”。这个习惯是我最庆幸养成的。错题不抄原题,只写“错在哪一步、正确思路是什么”,二十个字以内。考前只看这一块,比重新翻书有用得多。
6.4 几个当时卡了很久的问题
“为什么 TCP 需要序号又需要确认号”——因为两个方向各自独立编号,序号标识自己发的数据流位置,确认号标识期望对方下次发的位置,两者不是一回事。我当初把确认号理解成“对序号的回应”,结果乱了很久。
“为什么有了 IP 地址还需要 MAC 地址”——IP 是逻辑地址,标识“最终目的地在哪”,但在一段具体链路上,数据要靠硬件地址才能交付给下一跳。两者层级不同,缺一不可。
“为什么快重传要求三个重复确认而不是一个”——因为网络存在乱序,一个重复确认可能只是乱序导致的,三个重复确认说明大概率真的丢了。这个“为什么是 3”的问题我查了不少资料,答案就这一句:平衡误判和延迟。
7. 复习与输出:把笔记变成能讲出来的东西
7.1 三轮复习法,每轮目标不一样
第一轮只做一件事:合上笔记,把六块目录默写出来,每块下面写出三个核心概念。写不出来的地方就是漏洞,回头补。这一轮不追求细节,只追求“地图完整”。
第二轮做计算题。时延、带宽时延积、窗口、拥塞窗口变化、子网划分、最小帧长,每类抽两道,限时做完。做错的回到模板文件里补一条错因。
第三轮做输出。找一个人(哪怕是自己对着录音),用十分钟把“一次网页访问从输入网址到页面显示”讲完整,要求穿过全部五层,每层说清楚发生了什么。讲不顺的地方,就是还没掌握的地方。这一轮最痛苦,但提升最大。
7.2 面试和答辩里最常被追问的角度
整理下来,被问得最多的不是定义,而是“为什么这么设计”。比如为什么 TCP 头是 20 字节起步、为什么 IP 头有首部长度字段、为什么要分片、为什么 UDP 头只有 8 字节。这些问题在笔记里我都留了一行“设计动机”,复习时优先看这一行。
另一个高频角度是对比:TCP 和 UDP 怎么选、交换机和路由器怎么分工、距离向量和链路状态各适合什么场景。这类题没有标准答案,但要有判断依据。我的答法是先讲场景特点,再讲协议特性,最后给出取舍,而不是直接说“用 TCP 更可靠”。
还有一个容易被忽略的点:让你描述一次故障排查过程。这时候第 6 节那套从下往上的顺序就派上用场了,按顺序讲,条理自然清楚。
7.3 一点个人体会
这套笔记最后我留下了大概三十页手写、一个结构化的电子文档、一堆抓包截图和几个能跑的代码文件。回头看,真正让我从“会背”变成“会想”的,不是笔记本身,而是反复画时间轴、反复手算参数、反复把抓包结果和课本对上的那个过程。笔记只是把这些过程固定下来,方便回看。
如果你正在做这件事,我的建议是别急着把笔记做完整。先用抓包工具看一眼真实的三次握手,再回来写笔记,写出来的东西会完全不一样。另外,手算那部分千万别偷懒跳过去,公式看一眼觉得懂,动笔就会露馅,这个我试过不止一次。