from - zero
00. 从 0 开始理解计算机网络
0. 本章先解决什么问题
计算机网络解决的是:
一台机器上的进程
如何和另一台机器上的进程交换数据?
你在应用里看到的可能只是:
访问一个 URL
下载一个文件
发一条消息
调用一个远程接口
但底层要经过:
- 域名解析。
- 建立传输连接或选择无连接发送。
- 加密握手。
- 应用协议封装。
- 操作系统 Socket。
- IP 寻址和路由。
- 局域网帧传输。
- 网卡、中断、缓冲区。
- 对端反向解封装。
本章先建立全局地图,后面再逐层拆。
这张图怎么读
这张图是本模块的主图。以后看到任何网络现象,都先把它放回某一层:
| 现象 | 不要急着说 | 先放回哪层 |
|---|---|---|
| 域名解析不到 | 网络全坏了 | DNS / 命名系统 |
| 端口连不上 | 服务一定挂了 | TCP/UDP + 防火墙 + 监听状态 |
| 证书报错 | 应用逻辑错了 | TLS 身份认证 |
| 502/504 | 代码一定异常 | 代理、网关、上游路径 |
| 下载慢 | 带宽一定不够 | RTT、丢包、窗口、接收速度 |
1. 网络的最小模型
最小网络通信模型:
进程 A
-> 本机操作系统
-> 本机网卡
-> 中间网络设备
-> 对端网卡
-> 对端操作系统
-> 进程 B
通信本质是:
把数据从一个进程的地址空间
搬到另一个进程的地址空间
中间不能只靠一根“线”。必须解决:
- 对方是谁?
- 数据往哪里发?
- 中间设备怎么转发?
- 数据丢了怎么办?
- 顺序乱了怎么办?
- 数据是否被篡改?
- 对方身份是否可信?
- 发送太快怎么办?
- 网络拥塞怎么办?
2. 为什么要分层
网络太复杂,不分层就很难维护。
分层的思想:
每一层只解决一组问题
向上提供服务
向下依赖下一层能力
简化层次:
| 层 | 解决什么 |
|---|---|
| 应用层 | 应用语义:请求、响应、域名、网页、文件 |
| 传输层 | 进程到进程:端口、可靠性、流量控制 |
| 网络层 | 主机到主机:IP、路由、跨网络转发 |
| 链路层 | 相邻设备传输:MAC、帧、局域网 |
| 物理层 | bit 如何在介质上传输 |
每层都有自己的地址、数据单位、错误和边界。
3. 一次访问大致经过什么
访问:
https://example.com/index.html
可能经历:
解析域名
-> 得到目标 IP
建立 TCP 或 QUIC 连接
-> 和目标主机建立传输通道
TLS 握手
-> 认证身份,协商密钥
发送 HTTP 请求
-> 请求某个资源
服务器处理
-> 返回 HTTP 响应
本机接收数据
-> 解密、解析、交给应用
中间任何一步都可能失败。
4. 地址体系:不同层有不同地址
网络里有多种地址。
| 地址 | 层次 | 作用 |
|---|---|---|
| 域名 | 应用层 | 人类友好的名字 |
| IP 地址 | 网络层 | 标识网络中的主机或接口 |
| 端口 | 传输层 | 标识主机上的进程入口 |
| MAC 地址 | 链路层 | 局域网内相邻设备传输 |
例子:
www.example.com -> 93.184.216.34
目标端口 -> 443
下一跳 MAC -> 局域网里实际发送帧的目标
不要把域名、IP、端口、MAC 混成一类。
5. 数据单位:每层都有自己的包
| 层 | 数据单位 |
|---|---|
| 应用层 | message、request、response |
| 传输层 | segment 或 datagram |
| 网络层 | packet |
| 链路层 | frame |
| 物理层 | bit |
发送时封装:
应用数据
- 传输层头
- IP 头
- 链路层头尾
-> bit 流
接收时解封装:
bit
-> frame
-> packet
-> segment/datagram
-> 应用数据
6. 网络不保证一切
网络天然不可靠。
可能发生:
- 丢包。
- 重复包。
- 乱序。
- 延迟抖动。
- 带宽不足。
- 中间设备故障。
- 路由变化。
- MTU 限制。
- 对端关闭。
- NAT 状态过期。
- DNS 缓存错误。
不同协议在不同层补救一部分问题。
例如 TCP 解决可靠有序字节流,但它不解决:
- 应用消息边界。
- 对端业务是否处理成功。
- 数据是否应该被信任。
- 网络拥塞之外的应用排队。
反例:每一层都“成功”,端到端仍可能失败
网络学习里最危险的误判之一,是把某一层成功当作整条链路成功。
看一个请求:
DNS 成功解析
TCP 成功连接
TLS 成功握手
HTTP 请求成功发出
入口代理返回 200
客户端收到响应
这看起来已经全部成功,但端到端语义仍可能失败:
| 已成功的层 | 仍可能失败的事 |
|---|---|
| DNS | 解析到了旧地址或错误区域 |
| TCP | 对端进程接了连接,但业务线程池已满 |
| TLS | 身份和加密成立,但应用权限失败 |
| HTTP | 状态码 200,但响应体是错误页或旧缓存 |
| 代理 | 代理返回成功,但上游执行的是降级逻辑 |
| 客户端接收 | 客户端解析、校验、保存结果失败 |
所以端到端排障要最后回到业务语义:
数据是否被正确的对端处理?
处理结果是否符合协议和业务约定?
响应是否来自预期的层和版本?
分层给你定位工具,但最终成功条件由端到端语义定义。
7. 延迟和带宽
网络性能至少看两个维度:
| 指标 | 含义 |
|---|---|
| 延迟 | 一次数据往返或到达需要多久 |
| 带宽 | 单位时间最多能传多少数据 |
低延迟不等于高带宽。
高带宽不等于单次请求快。
影响延迟:
- 物理距离。
- 排队。
- DNS。
- 握手次数。
- TLS。
- 服务器处理。
- 丢包重传。
影响吞吐:
- 链路带宽。
- TCP 窗口。
- 拥塞控制。
- 接收方处理速度。
- 应用读写速度。
8. OS 在网络里的位置
应用通常通过 Socket 使用网络。
路径:
应用 buffer
-> 系统调用 send/recv
-> 内核 socket buffer
-> TCP/UDP/IP 协议栈
-> 网卡驱动
-> 网卡
所以网络问题可能在:
- 应用没有及时读写。
- 内核缓冲区满。
- event loop 被阻塞。
- 线程池耗尽。
- TCP 状态异常。
- DNS 失败。
- 路由失败。
- 对端慢。
网络不是只属于网络课,它和 OS 强连接。
9. 联系实际:一个请求慢怎么先拆
请求慢时,不要直接说“网络慢”。
按路径拆:
- 域名解析慢吗?
- TCP/QUIC 连接建立慢吗?
- TLS 握手慢吗?
- 请求是否成功发出?
- 服务端是否收到?
- 服务端处理慢吗?
- 响应是否已经返回?
- 客户端是否及时读取?
- 是否丢包、重传、拥塞?
- 是否代理、网关、负载均衡排队?
这就是网络排障的基本证据链。
这也可以变成一张排障卡:
| 阶段 | 你要看的证据 | 常见误判 |
|---|---|---|
| DNS | 解析耗时、解析结果、TTL | 把解析失败当成 TCP 失败 |
| TCP | connect 耗时、SYN/ACK、RST | 把端口拒绝当成应用 500 |
| TLS | 证书链、SNI、协议版本 | 把握手失败当成 HTTP 错 |
| HTTP | 状态码、Header、首字节时间 | 只看状态码,不看是谁返回的 |
| 下载 | 响应体大小、吞吐、重传 | 把大文件下载慢当成服务处理慢 |
一个适合自己练的小实验:访问同一个站点,分别记录 DNS、TCP、TLS、首字节、下载阶段耗时。你会发现“请求慢”很少是单一原因,慢点落在哪一段,解决方向完全不同。
手推:一次请求的延迟最少由哪些等待组成
把一次远程请求粗略拆开:
总耗时 =
DNS 查询
- 连接建立
- TLS/安全握手
- 请求上传
- 对端排队
- 对端处理
- 首字节返回
- 响应体下载
如果一次请求总共 1200ms,不要直接说“网络慢”。可能是:
| 阶段 | 耗时 |
|---|---|
| DNS | 5ms |
| 连接 | 30ms |
| TLS | 60ms |
| 请求上传 | 5ms |
| 对端排队 | 900ms |
| 对端处理 | 80ms |
| 首字节返回 | 20ms |
| 下载 | 100ms |
这种情况下主要慢点不是网络传输,而是对端排队。换一种情况:
| 阶段 | 耗时 |
|---|---|
| DNS | 700ms |
| 连接 | 30ms |
| TLS | 60ms |
| 处理 | 80ms |
| 下载 | 100ms |
主因就变成解析阶段。网络学习必须从“总耗时”拆到“阶段耗时”,因为不同阶段对应完全不同的机制和修复方向。
边界条件:丢包不是只有“完全断网”才会发生
网络失败不是二值的。很多时候不是完全不通,而是:
代码块收起展开
大多数包能到;
少量包丢失、乱序或延迟很高;协议通过重传和等待勉强恢复。
这会造成反直觉现象:
| 现象 | 可能解释 |
|---|---|
| 小请求正常,大响应慢 | 响应包多,更容易遇到丢包/重传 |
| 平均延迟还行,P99 很差 | 偶发重传或队列排队拉长尾部 |
| ping 偶尔丢 1% | 应用层可能出现明显尾延迟 |
| 带宽没满但下载慢 | 拥塞控制、窗口、丢包限制吞吐 |
所以网络排障不能只问“通不通”,还要问:
丢包率是多少?
重传是否增加?
延迟分布是否有长尾?
大包和小包是否表现不同?
排障卡:把“网络慢”拆成四段
当你听到一句“网络慢”,先不要急着猜协议。把一次访问拆成四段,每段只问一个可验证的问题:
| 阶段 | 核心问题 | 常见证据 | 更可能的方向 |
|---|---|---|---|
| 找到对方 | 名字能不能变成地址? | DNS 查询时间、解析结果是否变化 | 域名、缓存、解析链路 |
| 到达对方 | 包能不能走到目标网络? | ping / traceroute / 路由表 / 丢包率 | 路由、网关、防火墙、链路 |
| 建立会话 | 连接能不能完成? | SYN 重传、握手耗时、连接错误 | TCP 状态、端口、服务监听 |
| 传输数据 | 数据是否被及时处理? | 首字节时间、吞吐、重传、应用日志 | 拥塞、窗口、队列、服务处理 |
一个可操作的练习:找一个你常访问的网站,记录解析耗时、连接耗时、首字节时间和下载时间。然后思考:如果总耗时突然增加 2 秒,这 2 秒分别可能落在哪个阶段?你不需要立刻会所有工具,只要先学会把“慢”拆成可定位的问题。
10. 学完本章你能解决什么问题
学完这一章,你应该能解决或开始分析这些问题:
- 网络通信的目标为什么是进程到进程?
- 域名、IP、端口、MAC 分别属于哪一层?
- 为什么网络要分层?
- 封装和解封装是什么?
- 一次 HTTPS 请求大致经过哪些阶段?
- 网络为什么天然会丢包、乱序、延迟抖动?
- 延迟和带宽有什么区别?
- 请求慢时如何按 DNS、连接、TLS、应用、网络路径拆分?
计算机网络的核心不是“会背协议名”,而是能画出数据从一个进程到另一个进程的路径。