计算机网络这门课的第一章第一小节标题就五个单词——What is the Internet? 看起来像送分题实际上是最容易讲砸、也最容易被学过去的考点。我带过几轮某高校软件学院的这门课辅导也在实验室里给不少做上层应用的同学补过基础发现一个很普遍的现象很多人能把 TCP 三次握手背得滚瓜烂熟却说不清“端系统”“分组交换”“协议”这几个词在真实世界里对应的是什么。这一讲回答的不是“上网”这件事而是计算机网络这门学科用什么语言描述世界。它把 Internet 拆成两套互相咬合的描述体系一套讲组成端系统、通信链路、分组交换机、ISP、协议另一套讲服务它是一套为分布式应用提供支撑的基础设施。前者告诉你机器怎么摆后者告诉你程序怎么写。无论你是准备考试、准备面试还是准备自己动手写一个跨机器的服务这一讲都是地基。地基没打牢后面讲时延计算、分层封装、拥塞控制全都会变成背结论。1. 这一讲到底在解决什么问题1.1 先分清三个词网络、互连网、Internet很多同学一上来就把这三个词当同义词用这是第一个大坑。网络network指的是一组通过链路互相连接、能够彼此交换数据的设备集合规模可以很小两台笔记本用一根网线直连也算一个网络。互连网internet小写 i指的是把多个网络再连接起来形成的更大集合它是一个通用概念任何满足“网络的网络”这个结构的系统都能叫这个名字。Internet大写 I则是那个具体的、全球范围的、使用 TCP/IP 协议族的具体实例。这个区分听着像抠字眼但它直接影响你后面所有的表述准确性。考试里问“Internet 的组成”答成“很多电脑连在一起”是没有分的面试时被问到“你们这个系统部署在哪”如果回答“部署在互连网上”对方会立刻知道你概念没理清。我的建议是从第一节课开始就养成习惯写笔记时凡是泛指概念就写小写凡是特指那个全球系统就写大写一个月下来肌肉记忆就有了。之所以要花力气强调这一点是因为这一讲的标题用的是 “the Internet”带定冠词指的正是那个唯一的、具体的系统。教材在这里其实是在做一个定义工作给一个大家都以为自己懂的东西下一个能用于工程讨论的定义。1.2 为什么要给两种定义而不是一种教材给了两套描述一套叫“具体组成”讲端系统、链路、交换机、ISP、协议另一套叫“服务视角”讲它是一套为分布式应用提供服务的平台。初学者常有的疑惑是——直接说“一堆设备连起来”不就完了为什么还要再给一套原因在于这两种描述服务的读者根本不同。组成视角服务的是网络的建设者和运维者他们关心的是设备怎么摆、链路怎么接、流量怎么走、故障怎么定位。服务视角服务的是应用的开发者他们不关心中间经过了几台路由器只关心“我把数据交给它它能不能送到”“延迟大概多少”“会不会丢”。同一个系统从不同角色的切口看需要抽象掉的信息完全不同。这背后其实是计算机科学里一个反复出现的手法用抽象隐藏复杂度。你在写 Web 服务时调用一个 socket不需要知道下面走的是光纤还是同轴电缆也不需要知道中间跳了多少台设备。这个“不需要知道”不是无知而是被刻意设计出来的隔离层。理解这一点你才会明白后面讲分层、讲封装不是在背概念而是在维护这个隔离层的边界。注意考试里如果题目问“Internet 的服务模型是什么”答“提供可靠传输”是错的。Internet 的基础服务模型是“尽力而为best-effort”它不承诺带宽、不承诺时延、不承诺不丢包。可靠传输是 TCP 这个上层协议自己额外加出来的不是网络层给的。1.3 这一讲在整门课里的坐标从课程结构看这一小节是“概述”章的第一块砖后面紧跟着网络边缘、网络核心、时延与丢包、协议分层与安全。它的作用是先建立坐标系。你把这张地图建好了后面每讲一个具体协议你都知道它落在地图的哪个格子里。举个具体例子。后面讲 IP 协议如果你脑子里有“网络核心由分组交换机组成”这个概念你就能立刻定位路由器是网络核心里的设备它做的是转发转发的是分组分组里装着 IP 数据报。再往后讲 TCP你能立刻定位TCP 跑在端系统上不在路由器上跑。很多同学学了一学期还搞不清“路由器上到底有没有 TCP”根子就在第一章没建好坐标系。所以我的建议很直接这一讲不要急着背英文名词先花二十分钟拿一张空白纸自己画出“从你手机上的一个 App 到某台服务器”的完整路径把你能想到的每一类设备都标上去。画完再去对照教材的图缺什么补什么。这个动作比抄十遍笔记有用。2. 从组成看 Internet五个部件逐个拆2.1 端系统为什么主机要按角色分类端系统end system就是接在 Internet 边缘、能跑应用程序的设备手机、笔记本、服务器、智能音箱、车载终端都算。教材把它叫 end system是因为它处在网络的“两端”中间的部分负责把它们连起来。这个命名很形象也提醒你一件事真正产生价值的东西在端系统上中间的设备只是为了把数据搬过去。端系统按运行的角色分两类客户client和服务器server。这个分类经常被误解成“硬件等级”的划分好像服务器一定是台大机器。其实不是。一台普通笔记本跑个监听端口的程序它就是服务器一台大型机去请求别人的接口它就是客户。这个身份是由那次通信中的行为决定的不是由设备本身决定的。这一点在做分布式系统时特别重要。同一台机器上可以同时跑客户进程和服务器进程比如一个服务既对外提供 HTTP 接口又作为客户端去请求数据库。你如果在设计之初就把“服务器”当成一个固定角色很容易把架构做死。我见过有同学写课程项目把“服务器”写成一个全局单例结果需要两两通信时完全改不动只能推倒重来。实操心得判断一个进程是客户还是服务器只看一件事——谁主动发起连接。先发起连接的一方是客户被动等待连接的一方是服务器。这个判断标准在所有主流传输协议上都成立比看硬件可靠得多。2.2 通信链路与传输介质带宽差距有多大通信链路communication link是把端系统和分组交换机连起来的物理通道。教材列举了几类介质双绞铜线、同轴电缆、光纤、无线电。这里真正需要建立的感觉不是“有哪些介质”而是它们的速率差了几个数量级。家庭宽带常见的光纤接入单根光纤的容量可以做到很高双绞线在短距离内也能跑到千兆甚至更高无线电受限于频谱和干扰实际速率波动很大。你在做系统设计时的容量估算必须先搞清楚链路的量级。一个典型的新手错误是在本地千兆局域网里测试觉得“传输根本不是瓶颈”结果部署到跨地域环境同样的代码延迟涨了几十倍。链路还有一个容易忽略的属性是共享性。家里的 WiFi 是家人共享的公司的办公网是全公司共享的某些接入链路的带宽是若干用户分摊的。这意味着你测到的带宽随时会变不能当成恒定值写进容量模型。教材在讲接入网时会提到共享与专用的区别这个区别在实际排查问题时非常关键——用户投诉“网慢”十次里有好几次是共享链路在高峰时段被占满了。2.3 分组交换为什么不用电路交换分组交换机packet switch是网络核心里的设备主要分两类路由器和链路层交换机。它做的事情说起来很简单收到的数据不是一口气全部转发而是切成一个个分组packet每个分组带着目的地址交换机查表决定从哪个口发出去。为什么不学电话网那样通信前先建立一条独占的通路电路交换教材给的答案核心是统计复用。电话网的做法是通话期间这条通路的容量无论你有没有说话都被你占着。人说话其实是一阵一阵的中间有大量静默这些容量就浪费了。分组交换不预留谁有数据谁发链路容量被所有活跃用户共享利用率高得多。代价也很明确排队和丢包。多个人的分组同时到达一台交换机输出端口只有一个就得排队队列满了新来的分组只能丢掉。所以分组交换是用“不保证”换来了“高效率”。这个取舍你在后面的时延计算、拥塞控制里会反复遇到。注意教材里通常会问“分组交换一定优于电路交换吗”。答案是否定的。对实时性要求极高、流量恒定且需要连续性的场景预留资源的思路反而更合适。判断依据是流量特征突发型流量适合分组交换恒定速率流量适合预留资源。这个结论在面试里被问到的频率不低别只会答“分组交换更好”。2.4 ISP 与网络核心一张有商业结构的网Internet 不是一个平面的网而是由大量互相连接的 ISPInternet Service Provider网络服务提供方组成的层级结构。最底层是接入 ISP直接面向家庭和企业用户往上是区域级、国家级的主干 ISP再往上是少数几家一级骨干网。平级之间通过 IXP互联网交换点直接交换流量内容提供方也会自建网络尽量把内容推到离用户更近的地方。这套结构的存在解释了很多人困惑的现象为什么同一个服务在不同地区访问速度差很多为什么跨不同运营商的链路有时会明显变慢。因为数据包在物理上走的是商业关系决定的路径不是地理直线。你从 A 地访问 B 地的服务数据可能先绕到很远的交换点再折回来。理解这一点对你做部署选型有直接帮助。跨地域部署服务时除了看机房的硬件配置还要看它的网络接入位置和上游关系。同样的配置接在不同层级的 ISP 上用户感知可能差出一个量级。这不是玄学是路由路径的物理现实。2.5 协议这一讲真正的核心词如果这一讲只能记住一个词那就是协议protocol。教材用“人问路”做类比你走上前开口说“打扰一下”对方回“你说”你问“某地怎么走”对方回答。这一串交互之所以能成立是因为双方共享一套约定——什么时候开口、用什么语言、说什么内容、对方怎么回应。网络协议也是同一回事只是把参与方换成了机器。一个协议要定义三件事语法数据的格式和字段排列、语义每个字段表示什么、该做什么动作、时序谁先发、什么时候发、收到后怎么回。这三件事缺一不可。只有格式没有时序双方会僵持等待只有时序没有语义收到了也不知道怎么处理。教材里还会提到Internet 的标准由 IETF 发布的 RFC 文档定义业界的许多协议都遵循这套公开标准。这个特点很关键协议是公开的谁都可以实现。这正是不同厂商的设备、不同的操作系统、不同的语言写的程序能互相通信的根本原因。你在写代码时调用一个标准的 HTTP 客户端对方用什么语言写的服务器完全不重要因为大家遵守的是同一份约定。实操心得判断自己是否真的理解了某个协议用这个标准自测——能不能只靠文档手写一段原始报文让对方正确响应。能写出来说明语法语义时序三样你都掌握了写不出来说明你只是在调用封装好的库。3. 从服务看 Internet开发者视角的那一半3.1 尽力而为这个承诺到底意味着什么服务视角把 Internet 描述成“为分布式应用提供服务的基础设施”。这句话里最关键的是“服务”两个字而它提供的服务有一个明确的名字尽力而为best-effort。拆开说就是三条不保证送达不保证按顺序送达不保证在多长时间内送达。听起来很糟糕但这个设计是有意的。正因为不承诺网络核心才能保持简单才能承载任意类型、任意速率的流量。真正的可靠性被上移到了端系统由 TCP 这类协议在两端自己实现——确认、重传、排序、去重。这个分层思路非常值得学。把复杂的、需要状态的功能推到边缘让中间保持无状态和简单这个原则在后来的很多系统设计里都反复出现。你在做服务端架构时如果把所有状态都堆在中间层扩展性会立刻崩掉把状态放到客户端和存储层中间层只做转发才能横向扩容。理解“尽力而为”也就理解了为什么实时音视频要自己做缓冲和抗抖动为什么 HTTP 需要重试机制为什么长连接需要心跳。这些东西不是在补网络的漏洞而是在一个明确的服务模型之上由应用层自己补齐它需要的那部分保证。3.2 套接字服务视角的落脚点教材在讲服务视角时会提到套接字接口socket interface。这是应用程序和网络之间的边界。你可以把它想象成一个寄信的窗口你把信写好、填好地址、投进去剩下的事不用管收信的一方在另一个窗口把信取出来。这个比喻的重点在于接口两边是两套完全不同的世界。应用这边关心的是数据内容和业务逻辑网络那边关心的是分组怎么走。套接字把这两套世界隔开应用不需要知道底层是 WiFi 还是有线也不需要知道中间经过几台路由器。教材会列出应用可以请求的几种服务比如可靠数据传输、吞吐量保证、时延保证、安全性。不同的传输协议提供不同的组合。这也是为什么应用开发者必须知道自己在用什么协议——你需要的是“送到就行”还是“越快越好、丢一点无所谓”答案决定了你应该选哪一种。实际教学里我会让学生在第一周就写一个最小的两端通信程序一端监听端口另一端连上去发一行字符串收到后打印。代码很短但这一步跨过去后面所有的协议讲解都有了具体的对应物不再是纸上谈兵。3.3 两种视角怎么缝合跟一次请求走完全程把两种视角缝起来的最好办法是拿一次真实的请求走一遍。假设你在手机上点开一个页面。从服务视角看应用通过套接字接口发起请求DNS 先做名字解析建立连接发出请求报文等待响应拿到内容渲染。整个过程应用只和套接字打交道。从组成视角看同一件事手机通过无线链路接入某个接入点接入点到接入 ISP接入 ISP 进入核心网经过若干台分组交换机其中路由器做转发穿过可能存在的 IXP到达服务提供方的网络最终到那台服务器。每一步都是分组在链路上传输、在交换机上排队转发。两条线描述的是同一件事的不同层。服务视角是纵向的、以应用为中心的组成视角是横向的、以设备为中心的。你在排查问题时要学会在两条线之间切换应用报错先看服务视角检查连接、请求、响应如果服务视角一切正常但就是慢切到组成视角看路径、看链路、看哪一跳延迟高。4. 网络性能的四个基本量4.1 四种时延的拆解与手算教材在这一节给出一个非常实用的模型一个分组从 A 到 B 的总时延由四部分组成。处理时延是交换机检查分组头部、决定往哪转发所花的时间通常在微秒级排队时延是分组在输出队列里等待的时间波动最大取决于当前流量传输时延是把分组的比特推上链路的时间等于分组长度除以链路速率传播时延是信号在介质中走完这段距离的时间等于距离除以传播速度。必须强调传输时延和传播时延是两回事这是第一章最高频的混淆点。传输时延取决于分组多长、链路多快跟距离无关传播时延取决于距离和介质跟分组大小无关。一个形象的类比传输时延像“把一车货装上车的时间”传播时延像“车开过去的时间”。手算一遍。设一个分组长 1500 字节即 12000 比特链路速率 100 Mbps那么传输时延等于 12000 除以 100000000得 120 微秒。设两地距离 20000 公里光纤中信号传播速度约每秒 2×10⁸ 米传播时延约 0.1 秒也就是 100 毫秒。两者差了三个数量级。这解释了一个常被忽略的事实跨洲通信的延迟主要不是“数据多”而是“距离远”再大的带宽也压不下去。排队时延用一个无量纲的量刻画流量强度等于平均到达速率乘以分组长度再除以链路速率。这个值接近 1 时排队时延会急剧上升超过 1 时队列会无限增长现实中就是大量丢包。这就是为什么网络利用率不能做到 100%工程上通常希望留出明显余量。4.2 时延带宽积管道里到底装着多少数据时延带宽积等于传播时延乘以链路带宽含义是“这条链路在任意时刻‘在途’的数据量”。拿上面的例子100 Mbps 乘以 0.1 秒等于 10 兆比特约 1.25 兆字节。也就是说从发送方按下发送到第一个比特到达接收方这段时间里链路上已经塞进了 1.25 兆字节的数据。这个概念的意义在于它决定了要“填满”一条链路需要多大的窗口。如果你的发送窗口比时延带宽积小很多链路就永远跑不满带宽再大也没用。这就是为什么长距离高带宽链路需要更大的窗口和更激进的拥塞控制策略。很多同学做文件传输优化时发现加带宽没效果原因就在这里。4.3 丢包与吞吐量怎么定位瓶颈丢包的直接原因是队列溢出间接原因是流量强度过高或某处链路容量不足。定位方法很朴素沿着路径逐跳看哪一跳的延迟突然抬升、丢包率突然升高瓶颈大概率就在附近。吞吐量的定义是单位时间内成功传输的数据量。在一条由多段链路串起来的路径上端到端吞吐量约等于所有链路速率中的最小值这个最小值所在的链路叫瓶颈链路。这个结论看起来简单但它解释了大量现实问题家里升级到千兆宽带访问远端服务依然慢因为瓶颈在服务提供方的出口公司内网升级到万兆访问外部资源没变化因为瓶颈在出口线路。有一点要注意实际吞吐量通常小于理论值因为协议开销、确认机制、拥塞控制都会占用一部分容量。你测出来的数字大概只有标称值的七八成这是正常的不要以为是设备坏了。时延类型决定因素典型量级能否靠加带宽改善处理时延设备处理能力微秒级基本无关排队时延当前流量强度毫秒级波动大缓解但不消除传输时延分组长度、链路速率微秒到毫秒能传播时延物理距离、介质毫秒到百毫秒完全不能5. 分层这一讲埋下的最大伏笔5.1 为什么必须分层代价是什么教材在概述章末尾会引出分层。分层的目的很直接把一个极其复杂的系统拆成若干层每层只解决一类问题层与层之间通过明确的接口交互。好处有三条模块化一层换实现不影响其他层、复用上层不需要重复实现下层功能、分工不同的人可以负责不同的层。代价同样明显额外的开销和信息的冗余。每一层都要加自己的头部报文一层层套下去有效载荷占比下降。层与层之间的抽象也会屏蔽掉一些下层信息导致上层做出不优的决策——比如传输层看不到下面链路的实际状况只能靠探测推断。这个取舍在实际工程里随处可见。你做服务分层网关层、业务层、存储层分得越清楚改一处越容易但跨层调用的开销也越大。没有绝对正确的层数只有和当前规模匹配的层数。5.2 七层、五层、四层到底该记哪套教材通常会同时给出 OSI 七层模型和 TCP/IP 模型然后说明实际教学中采用五层结构。很多同学在这里崩溃到底背哪一套我的建议是以五层为主线另外两套作为对照记。五层是物理层、链路层、网络层、传输层、应用层。OSI 的会话层和表示层在实际协议栈里基本被合并进了应用层TCP/IP 模型则把物理层和链路层合在一起叫网络接口层。三套模型的差别主要在边界怎么划核心的分工是一致的。记住每一层的一句话职责比记住层名更重要物理层搬运比特链路层在一段链路上搬运帧网络层负责跨网络的寻址和转发传输层负责端到端的进程间通信应用层负责具体的业务语义。你把这句话背下来任何一道分层题都能往上套。5.3 封装与解封装数据下楼的全过程封装是分层思想的具体体现。应用层产生数据交给传输层传输层加上自己的头部比如源端口、目的端口形成报文段交给网络层网络层加上 IP 头部源地址、目的地址形成数据报交给链路层链路层加上帧头和帧尾MAC 地址、校验形成帧最后物理层把它变成信号发出去。接收方反过来一层层剥掉头部把数据交给对应的上层。这个过程中有一个容易被忽略的细节每一层只看得懂自己的头部。路由器在转发时拆到网络层就够了它不需要也不应该去看传输层的端口更不会去看应用层的内容。交换机拆到链路层就够了。这个“各看各的”正是分层能成立的前提。理解了封装很多现象就不用死记了。为什么 MTU 超了要分片因为链路层有帧长上限。为什么抓包时能看到多层头部嵌套因为你抓到的就是封装后的样子。为什么网络层的设备做不了内容过滤因为它根本不解析应用层。6. 课堂内外的坑与动手验证6.1 六个高频误区第一个误区是把 Internet 和万维网混为一谈。万维网只是跑在 Internet 上的众多应用之一邮件、文件传输、实时通信都不属于它。第二个误区是以为带宽就是“网速”。带宽是容量上限实际速度还受时延、丢包、协议开销影响。一条高带宽高时延的链路单次小请求照样很慢。第三个误区是以为 IP 地址和域名是一回事。域名是给人看的通过解析系统映射到地址一台主机可以有多个域名一个域名也可以对应多个地址。第四个误区是以为路由器上跑着完整的协议栈。路由器主要工作在网络层它不维护端到端的连接状态。第五个误区是以为分组交换在任何场景都更优。前面已经说过流量特征决定选型。第六个误区是把“可靠”理解成“快”。可靠传输保证的是送达和顺序为了做到这一点它需要确认和重传反而可能更慢。注意这六个误区在期末简答题里出现的频率极高很多时候不是不会而是表述不严谨被扣分。写答案时尽量把限定条件带上比如“在流量突发且对时延不敏感的场合”这类限定词是得分点。6.2 三个十分钟能做完的验证实验第一个实验看往返时延和丢包。用系统自带的连通性测试命令向一个目标连续发若干个小包观察每次的往返时间和丢包比例。你会看到时间不是恒定的会有小幅波动这个波动就是排队时延在变化。第二个实验看路径。用路由追踪命令观察数据到目标经过了多少跳每一跳的延迟是多少。你会看到某些跳的延迟突然抬升那就是跨网络边界的节点往往也是瓶颈所在。这个实验能非常直观地把“网络核心由分组交换机构成”变成你亲眼见过的东西。第三个实验看封装。用一个抓包工具抓一次普通的网页请求展开任意一个包你能清楚看到链路层头部、网络层头部、传输层头部、应用层内容一层层叠着。把每一层的字段和教材上的图对照一遍比看十遍图都有效。现象最可能的原因先查什么往返时间整体偏高但稳定物理距离远传播时延占主导路径跳数和地理跨度往返时间忽高忽低排队时延波动链路拥塞高峰时段对比、流量强度少量丢包但重传后正常队列溢出瞬时突发出口带宽利用率高带宽链路实际吞吐上不去窗口小于时延带宽积发送窗口、往返时延路径中某一跳延迟异常该节点或其上游链路拥塞逐跳延迟对比6.3 我在带实验时踩过的坑有一次让学生做吞吐量测试两组同学用同样的配置测出来的数字差了近十倍。查了半天发现一组在本地局域网内测试另一组跨了出口线路瓶颈根本不在同一处。这件事之后我改了个规矩做任何性能测试之前先让学生自己画出数据路径标出每一段的链路速率预判瓶颈在哪再去测。预判和实测对不上的地方就是最值得深挖的地方。还有一个坑是抓包位置选错。有同学在应用层日志里看到请求发出去了就以为数据已经上路实际上可能还堵在本地发送缓冲区里。抓包要抓在网卡出口日志要打在网络调用前后两个时间戳对不上问题就暴露出来了。我个人的体会是第一章这些概念之所以难不是因为它们抽象而是因为它们太“日常”日常到你以为自己懂了。真正检验有没有懂的标准很简单能不能用这些词准确地描述一次你亲手做过的请求从应用到链路一层不落地讲清楚。讲得清楚这一讲就真的过关了讲不清楚说明还停在背名词的阶段后面只会越学越吃力。