当前位置: 首页 > news >正文

深度解析 TCP 三次握手与四次挥手:从原理到 HTTP/HTTPS 的应用

TCP 的三次握手和四次挥手是网络通信的基石,无论是 HTTP 还是 HTTPS,它们都依赖 TCP 提供可靠的传输层服务。本文将用万字篇幅,结合 Mermaid 图表和代码示例,深入讲解 TCP 三次握手、四次挥手的原理、过程、状态变化,以及它们在 HTTP 和 HTTPS 中的应用场景。无论你是网络新手还是想深入理解 TCP 的开发者,这篇文章都会带你全面掌握这些核心机制!

1. TCP 协议概述

TCP(Transmission Control Protocol,传输控制协议)是互联网协议栈中的传输层协议,旨在提供可靠的、面向连接的、字节流传输服务。它确保数据包按序到达、无丢失、无重复,广泛应用于 HTTP、HTTPS、FTP 等协议。

TCP 的核心特性

  • 可靠性:通过序列号、确认机制和重传机制保证数据完整性。
  • 面向连接:通信前通过三次握手建立连接,通信后通过四次挥手断开连接。
  • 流量控制:通过滑动窗口避免发送方过载接收方。
  • 拥塞控制:通过算法(如慢启动、拥塞避免)适应网络状况。

TCP 在协议栈中的位置

应用层: HTTP/HTTPS
传输层: TCP
网络层: IP
数据链路层
物理层

图表说明

  • HTTP/HTTPS 运行在应用层,依赖 TCP 提供可靠传输。
  • TCP 封装数据为段(Segment),交给 IP 层传输。

2. TCP 三次握手详解

三次握手(Three-Way Handshake)是 TCP 建立连接的过程,确保双方准备好通信并协商初始序列号。它包含三次数据包交互,涉及客户端和服务器之间的状态转换。

2.1 三次握手的流程

三次握手的目的是建立可靠的连接,确保双方都能发送和接收数据,同时初始化序列号以跟踪数据传输。

三次握手流程图

客户端服务器SYN (seq=x)服务器: LISTEN ->> SYN_RECEIVEDSYN+ACK (seq=y, ack=x+1)客户端: SYN_SENT ->> ESTABLISHEDACK (ack=y+1)服务器: SYN_RECEIVED ->> ESTABLISHED数据传输客户端服务器

流程详解

  1. 第一次握手(SYN)

    • 客户端发送 SYN(Synchronize)包,包含初始序列号 seq=x
    • 客户端进入 SYN_SENT 状态,等待服务器响应。
    • 目的:通知服务器客户端希望建立连接,并提供初始序列号。
  2. 第二次握手(SYN+ACK)

    • 服务器收到 SYN 包,回复 SYN+ACK 包,包含自己的初始序列号 seq=y 和确认号 ack=x+1
    • 服务器从 LISTEN 状态进入 SYN_RECEIVED 状态。
    • 目的:确认收到客户端的 SYN,并表明服务器也准备好通信。
  3. 第三次握手(ACK)

    • 客户端收到 SYN+ACK 包,回复 ACK 包,包含确认号 ack=y+1
    • 客户端进入 ESTABLISHED 状态,服务器收到 ACK 后也进入 ESTABLISHED 状态。
    • 目的:确认双方都已准备好,连接正式建立。

状态转换图

服务器启动
客户端发送 SYN
收到 SYN,发送 SYN+ACK
收到 SYN+ACK,发送 ACK
收到 ACK
CLOSED
LISTEN
SYN_SENT
SYN_RECEIVED
ESTABLISHED
style
#FF6384
#36A2EB
#FFCE56
#4BC0C0
#36A2EB

关键点

  • 为什么需要三次握手?
    • 确保双方都能发送和接收数据(双向通信)。
    • 同步初始序列号,避免旧连接干扰。
    • 防止因网络延迟导致的错误连接(如重复的 SYN 包)。
  • 序列号的作用
    • TCP 使用序列号(Sequence Number)跟踪数据段的顺序。
    • 确认号(Acknowledgment Number)表示期望接收的下一个字节。

2.2 三次握手的代码模拟

以下是使用 Node.js 的简单代码模拟三次握手的概念(实际 TCP 握手由操作系统内核处理):

const net = require('net');// 服务器端
const server = net.createServer((socket) => {console.log('客户端发起连接 (SYN)');socket.write('SYN+ACK', () => {console.log('服务器响应 SYN+ACK');});socket.on('data', (data) => {if (data.toString() === 'ACK') {console.log('客户端确认 ACK,连接建立');socket.write('欢迎开始数据传输!');}});
});server.listen(8080, () => {console.log('服务器监听中 (LISTEN)');
});// 客户端
const client = new net.Socket();
client.connect(8080, '127.0.0.1', () => {console.log('客户端发送 SYN');client.write('SYN');
});client.on('data', (data) => {if (data.toString() === 'SYN+ACK') {console.log('收到 SYN+ACK,发送 ACK');client.write('ACK');} else {console.log('收到数据:', data.toString());}
});

运行结果

  1. 服务器启动,进入 LISTEN 状态。
  2. 客户端发送 SYN,模拟第一次握手。
  3. 服务器响应 SYN+ACK,模拟第二次握手。
  4. 客户端发送 ACK,模拟第三次握手,连接建立。

优化建议

  • 在实际应用中,TCP 握手由操作系统内核完成,开发者无需手动实现。
  • 确保服务器监听端口未被占用,避免握手失败。

3. TCP 四次挥手详解

四次挥手(Four-Way Handshake)是 TCP 断开连接的过程,确保双方有序关闭连接,避免数据丢失。

3.1 四次挥手的流程

四次挥手的目的是安全关闭连接,确保双方都完成数据发送并确认对方已收到。

四次挥手流程图

客户端服务器FIN (seq=x)服务器: ESTABLISHED ->> CLOSE_WAITACK (ack=x+1)客户端: FIN_WAIT_1 ->> FIN_WAIT_2FIN (seq=y)客户端: FIN_WAIT_2 ->> TIME_WAITACK (ack=y+1)服务器: CLOSE_WAIT ->> CLOSED客户端: TIME_WAIT ->> CLOSED客户端服务器

流程详解

  1. 第一次挥手(FIN)

    • 客户端(或服务器)发送 FIN(Finish)包,包含序列号 seq=x,表示不再发送数据。
    • 客户端进入 FIN_WAIT_1 状态。
    • 目的:通知对方客户端希望关闭连接。
  2. 第二次挥手(ACK)

    • 服务器收到 FIN,回复 ACK 包,包含确认号 ack=x+1
    • 服务器进入 CLOSE_WAIT 状态,客户端进入 FIN_WAIT_2 状态。
    • 目的:确认收到客户端的 FIN,允许服务器继续发送未完成的数据。
  3. 第三次挥手(FIN)

    • 服务器发送完剩余数据后,发送 FIN 包,包含序列号 seq=y
    • 服务器进入 LAST_ACK 状态。
    • 目的:通知客户端服务器也准备关闭连接。
  4. 第四次挥手(ACK)

    • 客户端收到 FIN,回复 ACK 包,包含确认号 ack=y+1
    • 客户端进入 TIME_WAIT 状态,等待一段时间(通常 2MSL,最大段生存时间)后进入 CLOSED 状态。
    • 服务器收到 ACK 后进入 CLOSED 状态。
    • 目的:确认双方都完成关闭,避免残留数据包干扰。

状态转换图

客户端发送 FIN
收到 ACK
收到 FIN,发送 ACK
发送 FIN
收到 FIN,发送 ACK
收到 ACK
等待 2MSL
ESTABLISHED
FIN_WAIT_1
FIN_WAIT_2
CLOSE_WAIT
LAST_ACK
TIME_WAIT
CLOSED
style
#36A2EB
#FFCE56
#4BC0C0
#FF6384
#36A2EB
#FFCE56
#4BC0C0

关键点

  • 为什么需要四次挥手?
    • TCP 是全双工通信,双方需要分别关闭发送方向的连接。
    • 四次挥手确保双方都完成数据发送并确认。
  • TIME_WAIT 的作用
    • 防止旧连接的数据包干扰新连接。
    • 确保服务器收到最后的 ACK,避免服务器无限等待。
  • 2MSL 等待时间
    • MSL(Maximum Segment Lifetime)是数据包在网络中的最大存活时间。
    • 2MSL 确保网络中残留的数据包失效。

3.2 四次挥手的代码模拟

以下是 Node.js 模拟四次挥手的概念(简化版):

const net = require('net');// 服务器
const server = net.createServer((socket) => {socket.on('data', (data) => {if (data.toString() === 'FIN') {console.log('收到客户端 FIN,发送 ACK');socket.write('ACK');setTimeout(() => {console.log('服务器发送 FIN');socket.write('FIN');}, 1000); // 模拟服务器处理剩余数据} else if (data.toString() === 'ACK') {console.log('收到客户端 ACK,服务器关闭连接');socket.end();}});
});server.listen(8080, () => {console.log('服务器监听中');
});// 客户端
const client = new net.Socket();
client.connect(8080, '127.0.0.1', () => {console.log('客户端发送 FIN');client.write('FIN');
});client.on('data', (data) => {if (data.toString() === 'ACK') {console.log('收到服务器 ACK');} else if (data.toString() === 'FIN') {console.log('收到服务器 FIN,发送 ACK');client.write('ACK');setTimeout(() => {console.log('客户端进入 TIME_WAIT,关闭连接');client.end();}, 2000); // 模拟 2MSL 等待}
});

运行结果

  1. 客户端发送 FIN,模拟第一次挥手。
  2. 服务器响应 ACK,模拟第二次挥手。
  3. 服务器发送 FIN,模拟第三次挥手。
  4. 客户端响应 ACK,进入 TIME_WAIT,模拟第四次挥手。

4. TCP 在 HTTP 和 HTTPS 中的应用

HTTP 和 HTTPS 都基于 TCP 提供可靠传输,下面分析它们如何利用三次握手和四次挥手。

4.1 HTTP 与 TCP

HTTP(HyperText Transfer Protocol)是应用层协议,运行在 TCP 之上,用于传输网页内容。

HTTP 请求流程图

客户端服务器三次握手SYNSYN+ACKACKHTTP 请求GET /index.html200 OK, HTML 数据四次挥手FINACKFINACK客户端服务器

关键点

  • 短连接(HTTP/1.0):每次请求都需要新的 TCP 连接(三次握手 + 四次挥手),开销较大。
  • 长连接(HTTP/1.1):通过 Connection: keep-alive,在同一 TCP 连接上复用多个请求,减少握手开销。

代码示例(HTTP 长连接)

GET /index.html HTTP/1.1
Host: example.com
Connection: keep-alive

优化建议

  • 使用 HTTP/1.1 或 HTTP/2 的长连接减少 TCP 握手次数。
  • 合并请求(如 CSS Sprites)减少连接需求。

4.2 HTTPS 与 TCP

HTTPS(HTTP Secure)在 HTTP 基础上通过 TLS/SSL 提供加密通信,但仍依赖 TCP。

HTTPS 连接流程图

客户端服务器三次握手SYNSYN+ACKACKTLS 握手Client HelloServer Hello, CertificateKey Exchange, Change Cipher SpecChange Cipher SpecHTTP 请求GET /index.html (加密)200 OK, HTML 数据 (加密)四次挥手FINACKFINACK客户端服务器

关键点

  • TLS 握手:在 TCP 三次握手后,HTTPS 额外进行 TLS 握手,协商加密算法和密钥。
  • 性能开销:TLS 握手增加延迟,但通过会话复用(Session Resumption)可优化。
  • 四次挥手:与 HTTP 相同,HTTPS 在数据传输完成后通过四次挥手关闭连接。

优化建议

  • 使用 TLS 1.3,减少握手轮次。
  • 启用会话复用(如 Session Tickets)减少 TLS 握手开销。
  • 使用 HSTS(HTTP Strict Transport Security)强制 HTTPS。

5. TCP 常见问题与优化

5.1 三次握手的问题

  • SYN 洪水攻击

    • 攻击者发送大量 SYN 包但不完成第三次握手,导致服务器资源耗尽。
    • 防御:使用 SYN Cookie,限制半连接队列大小。
  • 延迟影响

    • 三次握手增加初次连接的延迟,特别是在高延迟网络中。
    • 优化:使用 TCP Fast Open(TFO),在第一次握手时携带数据。

5.2 四次挥手的问题

  • TIME_WAIT 堆积

    • 客户端在 TIME_WAIT 状态等待 2MSL,可能导致端口耗尽。
    • 优化:调整系统参数(如 tcp_tw_reuse),或使用长连接减少挥手。
  • 半关闭状态

    • 服务器在 CLOSE_WAIT 状态停留时间过长,可能因未及时发送 FIN。
    • 优化:确保服务器及时关闭连接。

问题与优化对比图

问题
SYN 洪水攻击
TIME_WAIT 堆积
优化
SYN Cookie
TCP Fast Open
长连接

6. 完整流程总览

以下是 TCP 三次握手、四次挥手以及 HTTP/HTTPS 应用的完整流程图,清晰展示整个通信过程。

完整通信流程图

sequenceDiagramparticipant C as 客户端participant S as 服务器Note over C,S: 三次握手C->>S: SYN (seq=x)S->>C: SYN+ACK (seq=y, ack=x+1)C->>S: ACK (ack=y+1)Note over C,S: HTTPS: TLS 握手C->>S: Client HelloS->>C: Server Hello, CertificateC->>S: Key Exchange, Change Cipher SpecS->>C: Change Cipher SpecNote over C,S: HTTP/HTTPS 数据传输C->>S: GET /index.html (加密)S->>C: 200 OK, HTML 数据 (加密)Note over C,S: 四次挥手C->>S: FIN (seq=x)S->>C: ACK (ack=x+1)S->>C: FIN (seq=y)C->>S: ACK (ack=y+1)style C fill:#36A2EBstyle S fill:#FFCE56

图表说明

  • 三次握手:建立 TCP 连接,初始化序列号。
  • TLS 握手:HTTPS 额外协商加密参数。
  • 数据传输:HTTP/HTTPS 请求和响应。
  • 四次挥手:有序关闭连接,确保数据完整性。

7. 总结

TCP 的三次握手和四次挥手是网络通信的基石,确保了可靠的连接建立和关闭。HTTP 和 HTTPS 依赖 TCP 提供稳定传输,HTTPS 额外通过 TLS 握手实现加密。三次握手同步序列号,四次挥手确保数据发送完成,结合 Mermaid 图表和代码示例,我们清晰地展示了这些机制的原理和应用场景。

通过优化(如长连接、TLS 1.3、TCP Fast Open),我们可以显著提升网络性能。希望这篇文章能让你深入理解 TCP 握手与挥手机制,并在开发中更高效地应用 HTTP 和 HTTPS!

点个收藏,关注前端结城,一起用代码点亮前端世界!🚀

http://www.dtcms.com/a/316181.html

相关文章:

  • 微服务—OpenFeign
  • Spring中七种Propagation类的事务属性详解
  • 研发团队看板协作中的自动化实践:集成CI/CD与任务流转
  • 007TG洞察:高效运营Telegram私域流量:技术挑战与自动化解决方案探索
  • 中科米堆CASAIM自动化三维扫描系统自动测量压铸件尺寸
  • 【原创】基于gemini-2.5-flash-preview-05-20多模态模型实现短视频的自动化二创
  • 从 “看懂图” 到 “读懂视频”:多模态技术如何用文本反哺视觉?
  • 原型模式在C++中的实现与面向对象设计原则
  • 二维数点问题 1
  • 学习日志28 python
  • AI编程新时代:从氛围编程到上下文编程的深度实践和思考
  • 鸿蒙开发、大数据开发、Java开发与前端开发全面对比解析
  • 【银行测试】银行票据项目业务+票据测试点分析(四)
  • 2025《艾诺提亚失落之歌》逆向工程解包尝试
  • Linux网络编程:TCP初体验
  • VirtualBox安装教程
  • 64位程序调用32位dll方法
  • 【Linux系统编程】线程概念与控制
  • 使用valgrind工具检测server端lib库的内存泄漏
  • FT5X06 触摸芯片
  • 【技术教程】如何将 ONLYOFFICE 文档连接到 Confluence
  • nodejs 编程基础01-NPM包管理
  • Android 之 Kotlin
  • 让 Spark 干体力活:用 Java 快速找出最小值
  • GaussDB 并行创建索引
  • Webpack 5 Module Federation 模块共享最佳实践
  • AI智能体的安全困境:防护机制与伦理平衡的艺术
  • 高精度惯性导航IMU传感器供应商价格
  • Python-机器学习初识
  • C结构体的几种定义形式 + typedef结合使用的好处