计算机网络基础:从 TCP 连接到一次 HTTP 请求
背网络层次不难,难的是把它们串成一次真实请求:浏览器如何找到服务器,数据怎样逐层封装,TCP 为什么要握手,页面打不开时又该从哪里查起。本文沿着一次 HTTPS 请求,把这些问题连成一条线。
1. 先把分层模型放回实际网络
OSI 七层模型适合解释职责,日常排障更常按 TCP/IP 四层模型思考。两者不是两套互相竞争的协议,而是观察同一通信过程的不同粒度。
| TCP/IP 层次 | 大致对应的 OSI 层 | 典型协议或对象 | 主要问题 |
|---|---|---|---|
| 应用层 | 应用、表示、会话层 | HTTP、TLS、DNS | 传什么、怎样解释 |
| 传输层 | 传输层 | TCP、UDP | 哪个进程、是否可靠 |
| 网际层 | 网络层 | IPv4、IPv6、ICMP | 发往哪台主机、怎样路由 |
| 网络接口层 | 数据链路、物理层 | Ethernet、Wi-Fi、ARP | 下一跳是谁、怎样在链路上传输 |
发送时,应用数据会依次包进传输层报文段、IP 数据包和链路层帧;接收方再反向拆开。每一层只处理自己的地址与控制信息:端口定位进程,IP 地址定位主机,MAC 地址负责当前链路上的交付。
一个容易混淆的点是:交换机主要依据 MAC 地址转发帧,路由器主要依据 IP 地址转发数据包。数据跨过路由器后,链路层帧会重新封装,但端到端的源、目的 IP 通常保持不变;经过 NAT 时则可能被改写。
2. 输入网址后发生了什么
以访问 https://eulersail.com/ 为例,可以把主线压缩成下面几步:
flowchart LR
A[解析 URL] --> B[DNS 查询域名]
B --> C[选择路由与下一跳]
C --> D[建立 TCP 连接]
D --> E[TLS 握手与证书校验]
E --> F[发送 HTTP 请求]
F --> G[接收并渲染响应]
G --> H[复用或关闭连接]
DNS 先把域名解析成 IP 地址;本机根据路由表决定数据从哪个接口发出,并在局域网内解析下一跳的链路地址。随后建立传输连接。HTTPS 还要在 TCP 之上完成 TLS 握手,协商加密参数并验证服务器身份,最后才交换 HTTP 请求和响应。
因此,“网页打不开”并不等于“服务器宕机”。DNS、路由、端口、TLS 或 HTTP 任一环节失败,都可能在浏览器里表现为打不开。
3. TCP 三次握手
TCP 是面向连接的可靠字节流协议。连接建立时,双方不仅要确认对端可达,还要分别同步自己这一方向的初始序列号。
sequenceDiagram
participant C as 客户端
participant S as 服务器
C->>S: SYN,Seq=x
S-->>C: SYN + ACK,Seq=y,Ack=x+1
C->>S: ACK,Ack=y+1
Note over C,S: TCP 连接建立
- 客户端发送
SYN,声明自己的初始序列号x。 - 服务器回复
SYN + ACK:确认收到了x,同时声明自己的初始序列号y。 - 客户端发送
ACK,确认收到了y,双方进入ESTABLISHED。
逐步走完三次握手
点击发送报文,观察两端各自确认了什么,而不只是背 SYN、ACK 的顺序。
- 客户端SYN · Seq=x→服务器
- 客户端SYN + ACK · Seq=y · Ack=x+1←服务器
- 客户端ACK · Ack=y+1→服务器
第三次不能简单省略。服务器收到最后一个 ACK 后,才知道自己的发送方向也已被客户端确认。序列号与连接状态还能帮助协议栈识别网络中迟到的旧报文,避免把它误当作新连接的数据。
握手只说明连接已经建立,并不保证应用一定正常。端口可以接受 TCP 连接,但应用仍可能返回 HTTP 500,或在 TLS 阶段因证书、协议不兼容而失败。
4. “可靠传输”具体可靠在哪里
TCP 的可靠不是“网络永不丢包”,而是协议在丢包、乱序和接收能力变化时尽量向应用提供有序、不重复的字节流。
| 机制 | 作用 |
|---|---|
| 字节序列号 | 标记数据在字节流中的位置,用于排序和去重 |
| 确认应答 | 通常用累计 ACK 表示下一段期望收到的字节 |
| 超时与重传 | 未及时确认的数据会重新发送 |
| 快速重传 | 从重复 ACK 等信号更快推断丢失,而不只等待超时 |
| 校验和 | 检测传输中的比特错误 |
| 接收窗口 | 让发送方不要压垮接收方,这是流量控制 |
| 拥塞控制 | 根据网络状况调节发送速度,避免加剧拥塞 |
流量控制和拥塞控制解决的是两个问题:前者关心“接收端吃不吃得下”,后者关心“网络扛不扛得住”。窗口也不是越大越好;过大的在途数据会增加缓存占用,丢包时也可能带来更多重传成本。
TCP 交付的是字节流,没有天然的“消息边界”。应用协议必须自己定义边界,例如 HTTP 使用首部与内容长度,其他协议可能使用换行符、固定长度或长度字段。一次 send 并不保证对应接收端的一次 recv。
5. 连接关闭:FIN、半关闭与 RST
正常关闭通常被画成“四次挥手”:
sequenceDiagram
participant C as 客户端
participant S as 服务器
C->>S: FIN
S-->>C: ACK
Note right of S: 服务器仍可发送剩余数据
S-->>C: FIN
C->>S: ACK
Note over C,S: 连接关闭
TCP 是全双工的。一端发送 FIN,只表示自己不再发送数据,仍可以继续接收另一端尚未发完的数据,这就是半关闭。另一方向稍后也发送 FIN,双方分别确认。
“四次”是逻辑过程,不意味着抓包一定看到四个独立报文。若接收方恰好也准备关闭,它可能把 ACK 与自己的 FIN 合并发送。RST 则代表异常中止,例如目标端口没有监听、应用强制关闭,或协议栈判定连接不可继续。
6. 看懂常见 TCP 状态
stateDiagram-v2
[*] --> CLOSED
CLOSED --> SYN_SENT: 主动打开 / SYN
SYN_SENT --> ESTABLISHED: SYN + ACK / ACK
CLOSED --> LISTEN: 被动打开
LISTEN --> SYN_RECEIVED: 收到 SYN
SYN_RECEIVED --> ESTABLISHED: 收到 ACK
ESTABLISHED --> FIN_WAIT_1: 主动关闭
ESTABLISHED --> CLOSE_WAIT: 收到 FIN
CLOSE_WAIT --> LAST_ACK: 应用关闭
FIN_WAIT_1 --> FIN_WAIT_2: 收到 ACK
FIN_WAIT_2 --> TIME_WAIT: 收到 FIN / ACK
LAST_ACK --> CLOSED: 收到 ACK
TIME_WAIT --> CLOSED: 等待超时
| 状态 | 含义 | 排查提示 |
|---|---|---|
LISTEN |
本地进程正在等待连接 | 确认监听地址与端口是否正确 |
SYN_SENT |
已发 SYN,等待响应 | 检查路由、防火墙和目标端口 |
ESTABLISHED |
连接已建立 | 不代表应用响应一定健康 |
CLOSE_WAIT |
对端已关闭,本地应用尚未关闭 | 大量长期存在时重点检查应用是否释放连接 |
TIME_WAIT |
主动关闭方暂时保留连接信息 | 用于处理迟到报文并保证最终 ACK 可重传,少量出现属正常现象 |
不要一看到 TIME_WAIT 就调低内核等待时间。应先判断连接创建频率是否异常、能否复用长连接,以及应用是否合理管理连接池。大量长期 CLOSE_WAIT 往往比 TIME_WAIT 更直接地指向应用层关闭逻辑。
7. TCP 与 UDP 怎么选
| 对比项 | TCP | UDP |
|---|---|---|
| 连接 | 建立连接后传输 | 无连接数据报 |
| 交付抽象 | 有序字节流 | 保留数据报边界 |
| 可靠性 | 内置确认、重传、流量与拥塞控制 | 不内置可靠交付,应用按需实现 |
| 典型关注点 | 正确、完整、顺序 | 时延、简单、可定制 |
| 常见场景 | Web、数据库连接、文件传输 | DNS 查询、实时音视频、游戏状态更新 |
“实时业务一定用 UDP”也不准确。协议选择取决于是否允许丢失、是否需要顺序、网络环境与实现成本。QUIC 就运行在 UDP 之上,但在用户态重新实现了可靠传输、拥塞控制和加密握手等能力。
8. 一套由下到上的排障路径
排障时最好一次只验证一层,并记录“域名、IP、端口、时间点、错误信息”这五项上下文。
第一步:域名能否解析
1 | Resolve-DnsName eulersail.com |
也可以使用跨平台更常见的 nslookup eulersail.com。若解析失败,先检查 DNS 配置、记录是否生效以及本机缓存,不要急着怀疑 HTTP 服务。
第二步:目标端口能否建立 TCP 连接
1 | Test-NetConnection eulersail.com -Port 443 |
如果 DNS 正常而端口不通,再检查本机路由、云防火墙、安全组、服务监听地址与端口。tracert eulersail.com 可以辅助观察路径,但中间节点不响应探测并不等于业务流量一定不通。
第三步:TLS 与 HTTP 是否正常
1 | curl.exe -I https://eulersail.com/ |
-I 适合快速查看状态码与响应头,-v 能展示 DNS、连接、TLS 和 HTTP 交互细节。不要为了“临时成功”长期关闭证书校验;证书错误应从域名匹配、有效期、系统时间和证书链入手。
第四步:查看本机连接状态
1 | Get-NetTCPConnection | Sort-Object State |
端口与进程号只能说明“哪个进程占用连接”,还要结合应用日志、反向代理日志和同一时间点的请求 ID 判断根因。
9. 常见误区
- Ping 不通就是网站故障:ICMP 可能被禁用,而 TCP 443 仍然正常。
- TCP 建连成功就是接口正常:建连只验证到传输层,HTTP 仍可能超时或返回错误状态码。
- 三次握手是为了交换三次数据:核心是双方确认收发能力并同步序列号。
- 四次挥手永远对应四个包:ACK 与 FIN 可能合并,异常关闭还可能直接出现 RST。
- OSI 每层都有独立软件模块:它首先是职责模型,实际实现可能跨层优化或合并。
10. 小结
理解网络时,可以始终追问四个问题:数据属于哪一层、这一层使用什么标识、它保证了什么、失败时怎样单独验证。沿着 DNS、路由、TCP、TLS、HTTP 逐层缩小范围,比记忆孤立术语更接近真实工程。