深度解析 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.pswp.cn/news/917750.shtml
繁体地址,请注明出处:http://hk.pswp.cn/news/917750.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Hyper-V + Centos stream 9 搭建K8s集群(一)

一、创建虚拟机一台32G内存,16核心的Win11,已经安装了Hyper-V 管理器。然后也下载了CentOS-Stream-9-latest-x86_64-dvd1.iso的镜像文件。这里Hyper-V创建虚拟机的过程就不赘述了,如果出现虚拟机加载不到镜像的问题,先把这个使用安…

Pygame如何制作小游戏

以下是 Pygame 的详细使用指南,从安装到开发完整游戏的步骤说明,包含代码示例和最佳实践: 一、安装与环境配置 1. 安装 Pygame pip install pygame2. 验证安装 import pygame pygame.init() print(pygame.version.ver) # 应输出版本号&am…

@【JCIDS】【需求论证】联合能力集成与开发系统知识图谱

JCIDS(联合能力集成与开发系统)知识图谱 1. JCIDS概述 2. JCIDS的提出背景 3. JCIDS核心流程 4. JCIDS分析方法 5. JCIDS优势 6. JCIDS与采办系统的关系 7. JCIDS知识图谱结构 8. 对我的启示 9.JCIDS(联合能力集成与开发系统)相关术语列表 10. 参考文献 1. JCIDS概述 定义:…

每天学一个Linux命令(38):vi/vim

每天学一个 Linux 命令(38):vi/vim vi 和 vim(Vi IMproved)是 Linux 和 Unix 系统中功能强大的文本编辑器。vim 是 vi 的增强版,提供语法高亮、多级撤销、插件支持等更多功能。掌握 vi/vim 是 Linux 系统管理员的必备技能之一。 1. 命令简介 vi:经典的文本编辑器,几乎…

【PZ-ZU49DR-KFB】:璞致电子 UltraScale+ RFSoC 架构下的软件无线电旗舰开发平台

璞致电子 PZ-ZU49DR-KFB 开发板基于 Xilinx ZYNQ UltraScale RFSoC XCZU49DR 主控制器,以 "ARMFPGA 异构架构" 为核心,融合高带宽信号采集、高速数据处理与灵活扩展能力,专为专业工程师打造的软件无线电(SDR&#xff09…

力扣106:从中序与后序遍历序列构造二叉树

力扣106:从中序与后序遍历序列构造二叉树题目思路代码题目 给定两个整数数组 inorder 和 postorder ,其中 inorder 是二叉树的中序遍历, postorder 是同一棵树的后序遍历,请你构造并返回这颗 二叉树 。 思路 我们首先要知道中序遍历和后序…

IDEA JAVA工程入门

Maven配置: IDEA -> settings -> Build, Execution, Deployment -> Build Tools -> MavenMaven home pathUser setting file : 特定仓库下载依赖包,自动下载(界面右边M图标点开,)local repository (本地仓库&#xff…

Spring依赖注入:从原理到实践的自学指南

Spring依赖注入:从原理到实践的自学指南 一、什么是依赖注入? 依赖注入(Dependency Injection, DI)是Spring框架实现控制反转(IoC)的核心手段。其核心思想是:对象不再自己创建依赖项&#xff…

3_软件重构_组件化开发实例方法论

1、上期回顾上次内容核心的地方有两个,①是C多态基类的指针指向派生类,用于初始化各个插件。②是使用C语言的dlopen函数“动态加载”各个插件,实现用户根据契约接口自定义开发插件,极大程度地实现了软件上的解耦。③再进一步&…

C#接口的定义与使用

第1章 接口(interface)是什么1.1 定义• 接口是一组“能力”或“契约”的抽象描述,只规定“能做什么”,不规定“怎么做”。• 在 C# 中,接口是一种完全抽象的类型(fully abstract type)。 • 关…

【STM32】HAL库中的实现(三):PWM(脉冲宽度调制)

🔧 HAL库中的实现:PWM(脉冲宽度调制) PWM(Pulse Width Modulation)是基于定时器(TIM)产生的周期性脉冲信号,广泛应用于:① 电机调速;② LED 亮度控…

GitHub 趋势日报 (2025年08月03日)

🚀 GitHub 趋势日报 (2025年08月03日) 📊 由 TrendForge 系统生成 | 🌐 https://trendforge.devlive.org/ 🌐 本日报中的项目描述已自动翻译为中文 📈 今日获星趋势图 今日获星趋势图751dyad362LLMs-from-scratch291…

Java后端高频面试题

Java后端高频面试题 目录 Java集合框架Java并发编程JVM相关MySQL数据库Redis缓存Spring框架 Java集合框架 HashMap的数据结构是什么,为什么在JDK8要引入红黑树? HashMap数据结构: JDK7:数组 链表JDK8:数组 链表…

37. line-height: 1.2 与 line-height: 120% 的区别

概述 line-height 是 CSS 中用于控制文本行间距的重要属性。虽然 line-height: 1.2 和 line-height: 120% 看似相同,但它们在计算方式上存在关键区别,尤其是在继承和计算值方面。1. 计算方式不同写法类型计算方式说明line-height: 1.2无单位(…

蓝桥杯----DS1302实时时钟

(六)、DS1302实时时钟1、原理(图 二十六)DS1302通过三线串行接口与单片机进行通信。微控制器可以通过设置RST引脚为高电平来使能DS1302,并通过SCK引脚提供串行时钟信号,然后通过I/O引脚进行数据的读写操作。…

C++对象访问有访问权限是不是在ide里有效

在C中,对象的访问权限(即公有(public)、保护(protected)和私有(private)成员的访问)是编译时的一部分,而不是运行时。这意味着,无论是在IDE&#…

CubeMX安装芯片包

1.点击HELP2.选择公理嵌入式软件包3.选择并下载芯片包

【面向对象】面向对象七大原则

设计模式 设计模式是什么? 设计模式是一种针对于反复提出问题的解决方案,是经过长时间经验和试错而总结出来的一套业务流程; 其目的是为了提高代码的可重用性和可维护性,让代码更容易让人理解,保证代码可靠性&#…

《计算机“十万个为什么”》之 面向对象 vs 面向过程:编程世界的积木与流水线

《计算机“十万个为什么”》之 面向对象 vs 面向过程:编程世界的积木与流水线 🤖 想象你要造一辆汽车🔧: 面向过程 按手册一步步拧螺丝:拧紧螺栓A → 安装轮胎B → 焊接车架C 面向对象 召唤汽车人战队:引…

Visual Studio Code (VSCode) 的常用快捷键

Visual Studio Code (VSCode) 的常用快捷键可极大提升开发效率。以下是分类整理的 **核心快捷键**(基于 **Windows/Linux** 系统,macOS 用户将 Ctrl 替换为 Cmd,Alt 替换为 Option):⚡ 基础操作快捷键功能Ctrl N新建文…