教学目标
📖 课前导入
网络层(IP协议)负责把数据包从源主机送到目的主机,但它是不可靠的——不保证数据包一定到达,也不保证到达的顺序。
谁来保证数据传输的可靠性?答案是传输层的TCP协议!它提供面向连接的、可靠的、字节流服务。
今天我们来深入学习TCP——互联网上最重要的传输协议!
📚 一、TCP协议概述
TCP的核心特点
TCP(Transmission Control Protocol,传输控制协议)提供面向连接的、可靠的、基于字节流的传输服务。它是HTTP、FTP、SMTP、SSH等绝大多数应用层协议的底层传输。
面向连接
通信前先建立连接(三次握手)
可靠传输
确认、重传、排序保证数据完整
流量控制
接收方控制发送速率
拥塞控制
根据网络状况调整发送速率
📚 二、TCP报文段结构 ⭐核心内容
TCP首部格式(20字节固定 + 可变选项)
源端口 / 目的端口 —— 各16位
标识发送方和接收方的应用进程。范围0~65535。
序号(Seq)—— 32位
本报文段数据部分第一个字节的编号。TCP以字节为单位编号,保证数据按顺序重组。
确认号(Ack)—— 32位
期望收到对方下一个字节的编号。例如Ack=1001表示"1000及之前的数据我都收到了,请发1001"。
标志位 ⭐重要
窗口大小 —— 16位
接收方告诉发送方"我还能接收多少数据",用于流量控制。单位是字节。
📚 三、三次握手 ⭐⭐⭐必考
🎯 生活类比:打电话
小明拨号:"喂,你好,我是小明,能听到吗?" (第1次握手:我能发消息)
小红回应:"听到了!我是小红,你能听到我吗?" (第2次握手:我能收也能发)
小明确认:"听到了!那我们开始聊吧!" (第3次握手:双方确认完毕,开始通话)
💡 三次对话的目的:双方都确认了"我能听到你"且"你能听到我"。TCP三次握手道理完全一样!
🎬 TCP三次握手交互式动画
步骤 1 / 5客户端
CLOSED服务器
LISTEN初始状态:客户端关闭,服务器监听
💡 服务器已在端口上等待客户端连接请求
为什么需要三次握手?
TCP是面向连接的协议,通信前必须先建立连接。三次握手(Three-Way Handshake)有两个目的:
- 确认双方的发送和接收能力——确保客户端和服务器都能正常收发数据
- 同步初始序号(ISN)——让双方知道从哪个编号开始计数
═══ TCP 三次握手时序图 ═══
🔍 逐步详解
第一次握手:客户端 → 服务器
发送内容:SYN报文
SYN = 1(请求连接标志)
Seq = 1000(初始序号,随机生成)
ACK = 0(此时无确认)
🗣️ 通俗解读
"服务器你好!我是客户端,我想和你建立连接。我的起始编号是1000,以后我发的数据从这个编号开始。"
📌 客户端状态:CLOSED → SYN_SENT(已发送SYN,等待回复)
📌 服务器状态:LISTEN(一直在监听端口等待连接)
第二次握手:服务器 → 客户端
发送内容:SYN+ACK报文
SYN = 1(服务器也请求连接)
ACK = 1(确认收到客户端的SYN)
Seq = 2000(服务器的初始序号)
Ack = 1001(= 客户端Seq + 1)
🗣️ 通俗解读
"客户端你好!你的请求我收到了(ACK)。我也想和你建立连接(SYN)。我的起始编号是2000。你下次发数据请从编号1001开始(Ack=1001)。"
📌 客户端状态:SYN_SENT(还在等)
📌 服务器状态:LISTEN → SYN_RCVD(已收到SYN,等待最终确认)
⚡ 关键点:第二次握手做了两件事——①确认客户端的请求(ACK) + ②发送自己的连接请求(SYN),所以称为 SYN+ACK 报文。
第三次握手:客户端 → 服务器
发送内容:ACK报文
ACK = 1(确认收到服务器的SYN)
Seq = 1001(= 之前的Seq + 1)
Ack = 2001(= 服务器Seq + 1)
🗣️ 通俗解读
"服务器,你的回复我也收到了!连接正式建立,我们开始传数据吧!"
📌 客户端状态:SYN_SENT → ESTABLISHED(连接已建立!)
📌 服务器状态:SYN_RCVD → ESTABLISHED(连接已建立!)
✅ 此时双方状态都是 ESTABLISHED,可以开始双向数据传输了!第三次握手可以携带数据。
📊 三次握手确认了什么?
| 握手次数 | 客户端发送能力 | 客户端接收能力 | 服务器发送能力 | 服务器接收能力 |
|---|---|---|---|---|
| 第1次握手后 | ❓ | ❓ | ❓ | ✅ 确认 |
| 第2次握手后 | ✅ 确认 | ✅ 确认 | ✅ 确认 | ✅ 确认 |
| 第3次握手后 | ✅ 双方确认 | ✅ 双方确认 | ✅ 双方确认 | ✅ 双方确认 |
💡 第2次握手后客户端已知道双方能力正常,但服务器还不知道自己的SYN+ACK是否被客户端收到,所以需要第3次握手来确认。
为什么是三次?不是两次或四次?
❌ 两次握手的问题
假设客户端之前发了一个旧的SYN请求(因网络延迟还在路上),后来又发了新的SYN。如果只有两次握手:
- 旧SYN到达服务器 → 服务器以为是新请求,回复SYN+ACK → 错误地建立了连接
- 服务器白白分配资源等待数据,但客户端根本不会发数据 → 资源浪费!
✅ 三次握手的解决
客户端收到旧SYN对应的SYN+ACK后,发现序号不对,会发RST拒绝。三次握手让双方都有机会验证,避免了历史连接的混乱。
❌ 四次握手没必要
三次已经够了!第二次握手把SYN和ACK合并在一个报文中发送,没必要拆成两个。多一次就是浪费时间和带宽。
🌐 三次握手状态变迁图
🔬 Wireshark 抓包验证
用 Wireshark 抓包访问百度网站,可以清晰看到三次握手的真实数据:
📝 考试速记口诀
口诀一:SYN-SYN/ACK-ACK
第1次:客户端发 SYN
第2次:服务器回 SYN+ACK
第3次:客户端发 ACK
口诀二:请求-同意-确认
第1次:"我要连接" (请求)
第2次:"同意,我也要连接" (同意+请求)
第3次:"好的,开始吧" (确认)
⚠️ 易错点
- Ack(确认号)= 对方的Seq + 1,不要搞反
- 第三次握手时 SYN=0(不是1!),只有ACK=1
- 第三次握手可以携带数据,前两次不行
📚 四、四次挥手 ⭐⭐必考
连接释放——四次挥手
TCP连接的释放需要四次挥手(Four-Way Handshake)。因为TCP是全双工的,每个方向的关闭需要独立进行。
第1次挥手:客户端 → FIN
FIN=1, Seq=u | "我的数据发完了,请求关闭连接"
第2次挥手:服务器 → ACK
ACK=1, Ack=u+1 | "知道了,但我可能还有数据要发"
此时客户端→服务器方向关闭,但服务器→客户端方向仍可发数据(半关闭状态)
第3次挥手:服务器 → FIN
FIN=1, ACK=1, Seq=w | "我的数据也发完了,请求关闭"
第4次挥手:客户端 → ACK
ACK=1, Ack=w+1 | "好的,连接释放"
客户端进入TIME_WAIT状态,等待2MSL后才真正关闭
为什么需要TIME_WAIT?
客户端发送最后一个ACK后,不能立即关闭,而是等待2MSL(Maximum Segment Lifetime,最大报文生存时间)。原因:
- 确保最后的ACK能到达服务器(如果丢了,服务器会重发FIN,客户端可以再次确认)
- 等待本连接的所有残留报文在网络中消失,避免影响新连接
📚 五、流量控制与拥塞控制
流量控制(Flow Control)
目的:防止发送方发送过快,超出接收方的处理能力。
机制:接收方在ACK中通过窗口大小字段告诉发送方自己的接收缓冲区还剩多少空间。发送方据此调整发送量。
类比:水管往桶里灌水,桶快满时要减小水流。
拥塞控制(Congestion Control)
目的:防止过多数据涌入网络,导致网络拥塞崩溃。
机制:发送方维护一个拥塞窗口,根据网络反馈动态调整。
类比:高速公路堵车时要限流。
拥塞控制的四个阶段
1. 慢启动(Slow Start)
拥塞窗口从1MSS开始,每收到一个ACK翻倍增长(指数增长),直到达到慢启动阈值。
2. 拥塞避免(Congestion Avoidance)
超过阈值后,每个RTT窗口只增加1MSS(线性增长),小心探测网络容量。
3. 快重传(Fast Retransmit)
收到3个重复ACK时,立即重传丢失的报文段,不等超时。
4. 快恢复(Fast Recovery)
快重传后,阈值减半,窗口从新阈值开始线性增长(而不是从1开始)。
TCP三次握手与四次挥手动画详解
通过动画演示三次握手建立连接和四次挥手释放连接的完整过程,配合Wireshark抓包验证
通过动画演示三次握手建立连接和四次挥手释放连接的完整过程,配合Wireshark抓包验证
✅ 课堂小测
随堂测验
第 1/5 题TCP三次握手中,第二次握手的报文标志位是?
🧠 独立思考题
以下问题没有标准答案,需要你结合所学知识独立思考、小组讨论,锻炼分析问题的能力。
如果第三次握手的 ACK 丢了,会发生什么?
提示:思考以下几点——
- 此时客户端认为连接已建立,服务器呢?
- 如果客户端立刻发送数据,服务器会怎么处理?
- 服务器会一直等下去吗?还是有超时机制?
💡 思考方向
服务器处于 SYN_RCVD 状态,会重传 SYN+ACK。如果客户端此时发送了带 ACK 的数据包,服务器收到后也能确认连接。如果一直收不到,服务器最终超时关闭。
什么是 SYN 洪水攻击(SYN Flood)?它利用了三次握手的什么弱点?
提示:思考以下几点——
- 攻击者发送大量 SYN 请求,但故意不完成第三次握手
- 服务器会为每个"半连接"分配什么资源?
- 当半连接队列被占满后,正常用户还能连接吗?
- 你能想到什么防御方法?
💡 思考方向
每收到一个SYN,服务器就要在半连接队列中分配内存等资源。攻击者用伪造IP大量发SYN却不回ACK,导致队列溢出。防御方法包括:SYN Cookie(不分配资源,用算法验证)、限制半连接数、缩短SYN_RCVD超时等。
为什么建立连接需要三次握手,而释放连接需要四次挥手?能不能统一?
提示:对比思考——
- 建立连接时,服务器的 SYN 和 ACK 为什么能合并成一个报文?
- 释放连接时,服务器的 FIN 和 ACK 为什么不能合并?
- 关键区别在于:收到对方的关闭请求后,自己是否还有数据要发?
💡 思考方向
建立连接时双方都还没发数据,服务器可以立刻同意并发起自己的请求(SYN+ACK合并)。但释放连接时,服务器可能还有未发完的数据,必须先ACK确认收到关闭请求,等数据发完后再发FIN,所以ACK和FIN只能分开发。
你在浏览器输入 www.baidu.com 后按回车,这个过程中发生了几次三次握手?
提示:拆解整个过程——
- DNS 查询用的是 TCP 还是 UDP?需要三次握手吗?
- 访问 HTTP/HTTPS 网页需要和 Web 服务器建立 TCP 连接吗?
- 如果是 HTTPS,除了 TCP 握手,还需要什么握手?
- 页面中的图片、CSS、JS 文件需要分别建立连接吗?(想想 HTTP/1.1 的 Keep-Alive)
💡 思考方向
DNS查询通常用UDP(不需要三次握手)。访问百度至少需要1次TCP三次握手(连接Web服务器443端口),HTTPS还需要TLS握手。HTTP/1.1的Keep-Alive复用TCP连接,不需要对每个资源都重新握手。HTTP/2可以多路复用,一个连接传输所有资源。
三次握手有延迟代价(至少1.5个RTT),有没有办法减少这个延迟?
提示:了解这些技术——
- TCP Fast Open(TFO)是什么?它怎么在第一次握手就携带数据?
- QUIC 协议(HTTP/3)为什么能做到 0-RTT 连接?
- 这些"加速"方案有没有安全风险?
💡 思考方向
TCP Fast Open在首次连接时服务器发给客户端一个Cookie,之后客户端可在SYN中携带数据+Cookie,服务器验证Cookie后直接处理数据。QUIC基于UDP,将传输和加密握手合并,首次连接只需1-RTT,后续可0-RTT。但0-RTT存在重放攻击风险,需要额外防护。
👨🏫 教学建议
• 题目1-3:基础思考题,适合个人独立完成(5分钟)
• 题目4:综合应用题,建议2-3人小组讨论(8分钟)
• 题目5:拓展提升题,适合课后探索或翻转课堂
📋 本课小结
TCP特点:面向连接、可靠传输、流量控制、拥塞控制。
三次握手:SYN → SYN+ACK → ACK,建立双向连接并同步序号。
四次挥手:FIN → ACK → FIN → ACK,全双工两个方向分别关闭。
拥塞控制:慢启动→拥塞避免→快重传→快恢复,动态调整发送速率。