计算机网络
这一课你将能做到
- 对应 OSI 七层与 TCP/IP 四层模型,说出每一层解决什么问题、有哪些代表协议
- 描述 TCP 三次握手、四次挥手与可靠传输的基本机制,区分 TCP 与 UDP
- 说清一次 HTTPS 请求从 DNS 解析到 TLS 握手再到 HTTP 响应的完整链路
为什么要学
分布式系统的本质是「通过网络协作的多台计算机」。判题平台里几乎每个动作都在走网络:浏览器用 HTTPS 调后端接口,后端用 JDBC 连 MySQL、用 RESP 协议连 Redis,微服务之间走 HTTP/gRPC,判题结果通过 WebSocket 实时推给用户。
网络知识直接决定排查问题的能力:接口超时是连不上还是对端慢?DNS 偶尔解析失败怎么办?为什么 HTTPS 多一次往返?TIME_WAIT 太多端口耗尽怎么处理?只会 @GetMapping 无法回答这些问题。本课建立分层模型与三个关键协议(TCP、TLS、HTTP)的直觉。
先建立图像
分层模型对照(数据自上而下逐层加「信封」)
OSI 七层 TCP/IP 四层 代表协议/设备 典型问题
7 应用层 应用层 HTTP/HTTPS, DNS 状态码、接口语义
6 表示层 TLS, JSON, gzip 编码、加密
5 会话层 WebSocket
4 传输层 传输层 TCP / UDP 端口、可靠/快速
3 网络层 网际层 IP, ICMP 寻址、路由、ping
2 数据链路层 网络接口层 以太网, ARP, MAC 局域网内投递
1 物理层 网线/光纤/比特流
一次请求的旅程
浏览器
│ 1.DNS: 域名 → IP(递归查询:缓存→本地DNS→根→顶级→权威)
│ 2.TCP 三次握手建立连接
│ 3.TLS 握手:协商算法、交换证书与密钥(非对称加密换出对称密钥)
│ 4.HTTP 请求/响应(后续都用对称密钥加密)
▼
Nginx/负载均衡 ──▶ Spring Boot ──▶ MySQL/Redis
跟着做
步骤 1:亲手观察网络分层与连接
# 从下到上观察
ipconfig / ifconfig # 看本机 IP、MAC(网络接口层/网际层信息)
ping judge.example.cn # ICMP:测 IP 层连通性与延迟
nslookup judge.example.cn # DNS:看域名解析到哪个 IP
tracert judge.example.cn # Windows / traceroute:看经过哪些路由跳数
# 观察传输层连接(Linux/macOS)
netstat -an | grep ESTABLISHED # 或 ss -tan:看 TCP 连接状态
curl -v https://judge.example.cn/api/problems # -v 把 DNS、TCP、TLS、HTTP 全过程打出来
curl -v 是最值得养成的习惯:它依次打印解析到的 IP、TCP 连接建立、TLS 证书校验与加密套件协商、HTTP 请求头和响应状态码。一个命令看完整张分层图。
步骤 2:理解 TCP 三次握手与可靠传输
三次握手(建立连接,确认双方收发能力都正常)
客户端 服务端
── SYN, seq=x ───────▶ 我想连,我的序号是 x
◀── SYN+ACK, seq=y,
ack=x+1 ───────── 我收到了,也想连,确认你
── ACK, ack=y+1 ────▶ 确认你,连接建立
为什么不是两次?要防止一个迟到的旧连接请求突然到达,
白白让服务端建立连接并等待资源。
可靠传输四件套
序号 + 确认ACK:每个字节有序号,没收到确认就重传
超时重传: 计时器到期未确认 → 重发
滑动窗口: 批量发送而不是发一个等一个,流量控制
拥塞控制: 慢启动/拥塞避免,探测网络容量,避免灌爆网络
TCP vs UDP:TCP 面向连接、可靠、有序,代价是握手开销和头部较大(网页、文件、数据库连接都用它);UDP 无连接、不保证可靠但延迟低、头部小(DNS 查询、视频通话、游戏同步、QUIC/HTTP3 在 UDP 上自建可靠性)。判题平台的实时状态推送用 WebSocket(基于 TCP),对延迟敏感的判题心跳可考虑 UDP 但要自己补确认。
步骤 3:用 Java Socket 写一个最小 TCP 通信
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
public class MiniTcp {
// 判题 Worker:监听端口,收到题目ID后回送「已受理」
static class JudgeServer {
public static void main(String[] args) throws Exception {
try (ServerSocket server = new ServerSocket(9000)) {
System.out.println("判题机已启动,等待任务...");
try (Socket socket = server.accept();
BufferedReader in = new BufferedReader(
new InputStreamReader(socket.getInputStream()));
PrintWriter out = new PrintWriter(socket.getOutputStream(), true)) {
String problemId = in.readLine();
System.out.println("收到判题任务: " + problemId);
out.println("ACCEPTED:" + problemId);
}
}
}
}
// 调度中心:发起连接并发送任务
static class Scheduler {
public static void main(String[] args) throws Exception {
try (Socket socket = new Socket("localhost", 9000);
PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
BufferedReader in = new BufferedReader(
new InputStreamReader(socket.getInputStream()))) {
out.println("problem-1024");
System.out.println("调度中心收到: " + in.readLine());
}
}
}
public static void main(String[] args) {
new Thread(() -> {
try { JudgeServer.main(args); } catch (Exception e) { e.printStackTrace(); }
}).start();
Thread.sleep(500);
Scheduler.main(args);
}
}
这就是所有网络通信的骨架:IP 定位机器、端口定位进程内的程序、Socket 抽象出字节流。HTTP、JDBC、Redis 协议全部是在这个字节流上约定的「对话格式」。
步骤 4:HTTPS 与 TLS——在不可靠网络上建立可信通道
TLS 握手直觉(混合密码体系:非对称加密负责「安全地交换钥匙」,
之后用对称加密传输数据,因为对称加密快得多)
1. Client Hello:支持的 TLS 版本、加密套件、随机数
2. Server Hello:选定套件 + 随机数 + 数字证书(含公钥,由 CA 签名)
3. 客户端验证证书链与域名合法性,生成 pre-master secret,用服务端公钥加密发出
4. 双方用三个随机数算出会话密钥,互发 Finished 验证
5. 之后 HTTP 数据全部用会话密钥做对称加密 + 完整性校验
要点:证书解决「你连的服务器是不是真的」(信任链锚定到系统内置的根 CA);TLS 同时提供机密性(别人看不懂)和完整性(数据被篡改能发现),还防重放。生产中 Nginx/网关终止 TLS,内部链路可加密或在内网信任域内;证书过期是最常见的线上事故之一,要做到期监控。
讲清楚要点
- 分层的意义是分工与解耦:每层只解决一类问题并向上层提供服务;数据包在发送端逐层封装、接收端逐层解封。排查问题时按层定位(先 ping 再 curl),不要跨层乱猜。
- IP 负责「送到哪台机器」,端口负责「交给哪个程序」:端口 16 位,HTTP 80、HTTPS 443、MySQL 3306、Redis 6379;NAT 让多台内网机器共享公网 IP。
- TCP 的状态机要眼熟:LISTEN → SYN_SENT/RCVD → ESTABLISHED;主动关闭方进入 FIN_WAIT → TIME_WAIT(等待 2MSL,确保最后 ACK 到达和旧报文消亡)。高并发短连接下 TIME_WAIT 堆积会耗尽端口,解法是连接池、长连接、调内核参数。
- HTTP 是无状态的请求-响应协议:Cookie/Session、JWT 用来在无状态之上识别用户;常见状态码要会:301/302 重定向、304 协商缓存、400 参数错、401 未认证、403 无权限、404 不存在、429 限流、500 服务端错、502/503/504 网关与超时。
- DNS 是网络的电话簿:浏览器/OS 多级缓存 + 递归查询;它基于 UDP(快),响应过大或区域传送用 TCP;DNS 故障表现为「IP 能 ping 通但域名打不开」。
你可能会懵的地方
-
三次握手第三次握手丢了怎么办? 客户端认为连接已建立并可直接发数据;服务端处于 SYN_RCVD,它会重发 SYN+ACK。客户端若有数据发出,数据报文带 ACK,服务端收到也会转入 ESTABLISHED;若一直没确认,服务端超时后放弃。
-
为什么挥手要四次而握手三次? 握手时服务端的 SYN 和 ACK 可以合并成一条。挥手时 TCP 全双工,两个方向要分别关闭:收到 FIN 只表示对方没数据发了,但自己可能还有数据要发,所以 ACK 和自己的 FIN 通常分开发,共四次。
-
HTTPS 一定安全吗?中间人能不能攻击? 用户正确校验证书链时,中间人无法伪造可信证书,攻击会被浏览器警告。但如果用户信任了恶意根证书、设备被装了抓包代理、或应用代码关闭了证书校验(信任全部证书),HTTPS 就形同虚设——客户端安全同样重要。
-
HTTP/1.1、HTTP/2、HTTP/3 差在哪? 1.1 长连接复用但仍有队头阻塞(一个请求慢,后面排队);2 改为二进制分帧、多路复用、头部压缩;3 基于 QUIC(UDP),解决 TCP 层队头阻塞、握手更快、连接迁移好。Spring Boot 3 + 现代 Nginx 已可开启 HTTP/2。
-
连数据库用连接池和网络有什么关系? TCP 三次握手 + 认证有往返成本,频繁建连还会产生 TIME_WAIT 堆积;连接池复用长连接,同时限制数据库连接总数,是「网络成本 + 数据库负载」双方面的优化。
错法对照
| 错法 | 问题 | 正解 |
|---|---|---|
| 接口不设超时(connect/read timeout) | 对端挂起时线程被无限拖住 | 两类超时都设,配合重试与熔断 |
| 失败就无脑重试三次 | 非幂等操作重复执行、放大故障 | 仅对幂等请求重试 + 指数退避 + 总次数上限 |
| 内网调用走公网域名/公网 IP | 延迟与带宽成本、安全面扩大 | 内网 DNS/VIP/服务发现直接通信 |
| 代码里写死 IP 或第三方地址 | IP 变更即故障 | 域名 + 配置中心;监控 DNS 与证书 |
| 高并发用短连接且不监控端口 | TIME_WAIT 堆积、端口耗尽 | 连接池/长连接,监控连接状态分布 |
卡点急救
- 接口偶发超时:先
ping/curl -v分段测量——是 DNS 慢、TCP 建连慢、TLS 慢还是响应慢;再看对端负载与网络丢包,不同环节不同解法。 - 域名整体打不开:用
nslookup对比公共 DNS(如 223.5.5.5、8.8.8.8)判断是否解析故障; hosts 被改、权威 DNS、注册过期都可能,逐级排查。 - 服务出现大量 502/连接重置:检查后端是否重启、keep-alive 配置是否两端一致、连接池是否把已被对端关闭的连接发给了对方(开启连接有效性检测)。
面试常问
-
从输入 URL 到页面展示发生了什么?(后端版) DNS 解析得到 IP;TCP 三次握手;TLS 握手交换证书与会话密钥;发送 HTTP 请求,经负载均衡到 Spring Boot;服务查缓存/数据库返回响应;浏览器渲染。能再深入讲 ARP、路由、NAT、CDN 是加分项。
-
TCP 如何保证可靠传输? 字节序号与确认应答、超时重传、滑动窗口做流量控制、拥塞控制(慢启动、拥塞避免、快重传快恢复)、校验和与去重。可靠性是这些机制叠加的结果。
-
TLS 握手为什么要用非对称加密?为什么之后又改用对称加密? 非对称加密解决在不安全信道上安全协商密钥的问题(公钥可公开、私钥解密),但计算昂贵;对称加密速度快,适合大批量数据。TLS 用前者安全换钥匙、用后者高效传内容,是混合密码体系的标准设计。
自测三问
- 不看资料默画 OSI/TCP-IP 对照表,并各层写一个协议或排查命令。
- 解释 TIME_WAIT 为什么存在、什么情况下会出问题、至少两种缓解手段。
- 判题平台从 HTTP 升级到 HTTPS,链路上哪些组件要改?证书过期前如何发现?
小结一句话
网络靠分层把「比特投递、机器寻址、进程通信、加密信任、应用语义」逐级解决——TCP 让字节流可靠有序,TLS 让它机密可信,HTTP 让它有业务含义,理解分层就掌握了排查分布式故障的路线图。
延伸
- 《计算机网络:自顶向下方法》配套资源(Kurose & Ross)——网络入门权威教材,自顶向下契合后端视角
- MDN:HTTPS 与 TLS 工作原理——TLS 机制的权威通俗讲解
- RFC 9110:HTTP 语义(IETF 官方规范)
- 下一课:系统设计入门——单机、单库、单网络链路都清楚之后,学习把多个组件组合成可扩展的系统:容量估算、负载均衡与缓存。