每天我们都在和 TCP/IP 打交道:刷网页、看视频、聊微信。但当 HTTP 请求到达服务器时,数据是怎么一层层”剥洋葱”传递的? 本文从最基础的概念讲起,带你穿透协议栈,理解每一次网络通信背后的原理。
一、为什么需要协议 想象一个没有协议的世界:你写的数据,对方根本看不懂。就像两个人说话如果语言不通,只能鸡同鸭讲。
协议就是通信双方约定的规则 :
二、网络分层模型 OSI 七层模型(理论) 1 2 3 4 5 6 7 7 应用层 ← HTTP、FTP、DNS、SMTP 6 表示层 ← 数据格式、加密 5 会话层 ← 建立/维护会话 4 传输层 ← TCP、UDP 3 网络层 ← IP、ICMP、ARP 2 数据链路层 ← 以太网、Wi-Fi 1 物理层 ← 网线、光纤、无线电
TCP/IP 四层模型(实际) 1 2 3 4 4 应用层 ← HTTP、DNS、SSH 3 传输层 ← TCP、UDP 2 网络层 ← IP、ICMP 1 网络接口层 ← 以太网、ARP
每层只关心自己的事 ,通过接口 与上下层通信。这种设计的好处是解耦 ——改一层的实现不影响其他层。
三、数据封装过程(发送方) 1 2 3 4 5 6 7 8 9 应用层: [HTTP 请求数据] ↓ 加 HTTP 头 传输层: [TCP 头 | HTTP 数据] ↓ 加 TCP 头 网络层: [IP 头 | TCP 头 | HTTP 数据] ↓ 加 IP 头 链路层: [帧头 | IP 头 | TCP 头 | HTTP 数据 | 帧尾] ↓ 加帧头帧尾 物理层: 10101010100011010... (比特流)
接收方则是逆向解封装 ,像剥洋葱一样一层层去掉头部。
四、TCP 详解(传输层核心) 1. TCP 头部格式 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Source Port | Destination Port | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Sequence Number | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Acknowledgment Number | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Data | |U|A|P|R|S|F| | | Offset| Reserved |R|C|S|S|Y|I| Window | | | |G|K|H|T|N|N| | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Checksum | Urgent Pointer | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2. 关键字段 源端口、目的端口 :区分应用序列号 :标识数据字节位置确认号 :期望收到的下一个字节窗口大小 :流量控制标志位 :SYN、ACK、FIN、RST 等3. 三次握手(建立连接) 1 2 3 4 5 6 7 8 Client Server |--- SYN, seq=x -------------->| | | |<-- SYN+ACK, seq=y, ack=x+1 --| | | |--- ACK, seq=x+1, ack=y+1 --->| | | [连接建立]
为什么要三次而不是两次?
为了防止已失效的连接请求突然传到服务器 导致错误。如果是两次,网络延迟的旧请求到达服务器,服务器以为建立连接但客户端已经放弃,造成资源浪费。
4. 四次挥手(断开连接) 1 2 3 4 5 6 7 8 9 10 Client Server |--- FIN, seq=x -------------->| | | |<-- ACK, ack=x+1 -------------| | | |<-- FIN, seq=y ---------------| | | |--- ACK, ack=y+1 ------------>| | | [等待 2MSL 后关闭]
为什么是四次?
因为 TCP 是全双工的,客户端说”我说完了”,服务器也要说”我也说完了”。两次只能关一个方向。
5. 状态机 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 LISTEN | SYN v +-- SYN_SENT ---+ | | SYN+ACK v v SYN_RCVD <----- SYN_RCVD | ACK | ACK v v ESTABLISHED ESTABLISHED | FIN v FIN_WAIT_1 ---+ | ACK | FIN v v FIN_WAIT_2 CLOSE_WAIT | FIN | FIN+ACK v v TIME_WAIT LAST_ACK | | ACK +--- CLOSED <---+
6. 流量控制(滑动窗口) 问题 :发送方太快,接收方来不及处理。
解决 :接收方告诉发送方自己的窗口大小(缓冲区剩余空间)。
1 2 接收方窗口 = 64KB 发送方最多发送 64KB 数据,等 ACK 后才能发更多
7. 拥塞控制 问题 :网络本身拥塞,大量包丢失重传更糟。
解决 :四个核心算法
慢启动 :从 1 个 MSS 开始,每收到 ACK 翻倍(指数增长)拥塞避免 :达到阈值后线性增长快重传 :收到 3 个重复 ACK 立即重传快恢复 :跳过慢启动,直接进入拥塞避免1 2 3 4 5 6 7 8 9 10 cwnd ^ | /\ | / \ ← 拥塞发生,阈值减半 | / \ | / \____ 慢启动阈值 | / \ | / \____ 拥塞避免(线性) | / +-------------------------> 时间
8. 抓包实战 1 2 3 4 5 6 7 8 9 10 11 12 13 yum install -y tcpdump tcpdump -i eth0 port 80 -A -s 0 tcpdump -i eth0 port 80 -nn 12:00:00.000 IP 192.168.1.10.54321 > 192.168.1.20.80: Flags [S], seq 100 12:00:00.001 IP 192.168.1.20.80 > 192.168.1.10.54321: Flags [S.], seq 200, ack 101 12:00:00.002 IP 192.168.1.10.54321 > 192.168.1.20.80: Flags [.], ack 201
Flags 含义:
S = SYN. = ACKF = FINR = RSTP = PSH(推送数据)五、UDP 详解 UDP(User Datagram Protocol)极简:
1 2 3 4 5 +----------+----------+----------+----------+ | Src Port | Dst Port | Length | Checksum | +----------+----------+----------+----------+ | Data | +--------------------------------------+
UDP 特点 无连接 :直接发,不握手不可靠 :不保证送达、不保证顺序无流量控制 :发就完了轻量 :头部只有 8 字节适用场景 DNS 查询 视频/语音通话(偶尔丢包不致命) 实时游戏 广播/组播 UDP 真的会”丢包”吗? 会,而且 UDP 也不通知你。靠应用层处理 :
六、IP 协议(网络层) 1. IP 地址 IPv4:32 位,4 段十进制,共 43 亿个地址。
1 2 3 4 5 6 A 类:1.0.0.0 - 126.255.255.255 (大型网络) B 类:128.0.0.0 - 191.255.255.255 (中型) C 类:192.0.0.0 - 223.255.255.255 (小型) D 类:224.0.0.0 - 239.255.255.255 (组播) E 类:240.0.0.0 - 255.255.255.255 (实验)
2. 子网掩码 1 2 255.255.255.0 = /24 = 前 24 位是网络号,后 8 位是主机号 192.168.1.0/24:网络 192.168.1.0,主机 1-254
3. CIDR 与 VLSM 无类域间路由,灵活划分网络。
4. IPv6 128 位,理论上 2^128 个地址,几乎用不完。
1 2001:0db8:85a3:0000:0000:8a2e:0370:7334
七、应用层协议 HTTP 演进史 1 2 3 4 5 HTTP/0.9 (1991):只有 GET,纯文本 HTTP/1.0 (1996):支持 POST、HEAD、状态码 HTTP/1.1 (1997):持久连接、管道、分块传输 HTTP/2 (2015):二进制、多路复用、HPACK 压缩 HTTP/3 (2018):基于 QUIC(UDP),彻底解决队头阻塞
HTTP 请求流程 1 浏览器 → DNS 解析 → TCP 连接 → 发送请求 → 接收响应 → 渲染页面
HTTPS = HTTP + TLS 1 2 3 4 5 6 7 Client Server |--- Client Hello ------->| (支持的加密算法、随机数) |<-- Server Hello --------| (选定的算法、证书) |--- Key Exchange ------->| (用证书公钥加密 pre-master secret) |<-- Finished ------------| |--- Finished ----------->| | [加密通信开始] |
TLS 1.3 把握手从 2-RTT 降到 1-RTT,甚至 0-RTT。
八、DNS 详解 1. 域名层级 1 2 3 4 . (根域) └── com (顶级域 TLD) └── example.com (二级域) └── www.example.com (子域)
2. 解析过程 1 2 浏览器缓存 → 系统缓存 → hosts → LocalDNS → 根 DNS → 顶级 DNS → 权威 DNS → 返回 IP
3. 记录类型 A :域名 → IPv4AAAA :域名 → IPv6CNAME :域名 → 域名(别名)MX :邮件服务器NS :权威 DNS 服务器TXT :任意文本(SPF、DKIM 验证)4. DNS 命令实战 1 2 3 4 5 6 7 8 9 10 11 12 dig example.com dig @8.8.8.8 example.com dig +trace example.com nslookup example.com host example.com
九、网络排查工具 1. ping 测试连通性。
2. traceroute 查看路径。
3. netstat / ss 查看连接。
1 2 ss -tulnp ss -tan | head
4. tcpdump 抓包分析。
1 tcpdump -i any host 8.8.8.8 and port 53
5. Wireshark 图形化抓包工具,网络协议学习的瑞士军刀 。
十、性能优化实战 1. TCP 优化参数 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 net.ipv4.tcp_max_syn_backlog = 65535 net.ipv4.tcp_tw_reuse = 1 net.ipv4.tcp_tw_recycle = 1 net.core.somaxconn = 65535 net.ipv4.tcp_rmem = 4096 87380 6291456 net.ipv4.tcp_wmem = 4096 65536 6291456 net.ipv4.tcp_congestion_control = bbr
2. HTTP/2 优化 多路复用:一个连接并发多个请求 头部压缩:HPACK 算法 服务端推送(已废弃) 3. CDN 加速 静态资源分发到边缘节点 智能调度到最近的节点 减少回源 十一、安全相关 1. SYN Flood 攻击 攻击者发大量 SYN 不回 ACK,占满半连接队列。
防御 :SYN Cookie(net.ipv4.tcp_syncookies = 1)、防火墙、专业 Anti-DDoS 设备。
2. ARP 欺骗 局域网内发送伪造 ARP 包,拦截流量。
防御 :静态 ARP 绑定、ARP 防火墙。
3. HTTPS 中间人攻击 攻击者在客户端和服务端之间伪造证书。
防御 :客户端校验证书、HSTS、Certificate Pinning。
十二、深入学习路径 推荐书籍 《TCP/IP 详解 卷 1:协议》(W. Richard Stevens) 《计算机网络:自顶向下方法》(Kurose) 《HTTP 权威指南》(David Gourley) 《图解 HTTP》(上野宣) 在线资源 实战 用 Wireshark 抓自己电脑的 HTTP 请求,逐字段分析 用 Python 写一个简单的 Socket 客户端/服务器 部署一个网站,自己抓包看完整过程 总结 TCP/IP 协议栈看似复杂,但核心思想很简单 :
分层 :每层只管自己的事封装 :发送时层层打包,接收时层层解包可靠性 :TCP 用握手、确认、重传保证数据不丢效率 :滑动窗口、拥塞控制优化传输理解了这些,你再看任何网络问题:
为什么 502? 后端没响应 → TCP 连接失败 为什么慢? 网络拥塞或服务器处理慢 为什么丢包? 路由器过载或链路不稳 网络协议是程序员的底层能力 ,越深入学习,你解决问题的能力就越强。