TCP详解之三次握手和四次挥手

news2025/1/20 0:59:48

TCP详解之三次握手和四次挥手

1. TCP基本认识

1.1 什么是 TCP

TCP是面向连接的、可靠的、基于字节流传输层通信协议。

1.2 TCP协议段格式

我们先来看看TCP首部协议的格式

TCP头部协议格式

我们先来介绍一些与本文关联比较大的字段,其他字段不做详细阐述。

序列号:在建立连接时,由计算机随机生成的数作为初始值,通过SYN报文传给接收端。每发送一次,就累加一次该数。用来网络包乱序问题问题。

确认应答号:指下次期望收到的数据的序列号,发送端收到这个确认应答后可以认为这个序号以前的数据都被接收端正常接收了。用来解决丢包问题。

标志位:

  • ACK:该位为1时,确认应答字段是否有效
  • RST:该位为1时,表示TCP连接中出现异常,必须强制断开连接。
  • SYN:该位为1时,表示希望建立连接,并在序列号字段进行序列号初始值的设定。
  • FIN:该位为1时,通知对端以后不会有数据发送,希望断开连接。当通信结束希望断开连接。

1.3 为什么需要 TCP 协议

IP层是不可靠的,它不保证网络包的交付、不保证网络包的按序交付、也不保证网络包中数据的完整性。

如果需要保障网络数据包的可靠性,就需要上层 传输层TCP协议来负责。

因为TCP是一个工作在传输层可靠数据传输服务,它能确保接收端接收的网络包是无损坏的、无间隔的、非冗余和按序的。

2. TCP连接建立

2.1 TCP三次握手过程是怎样的

TCP是面向连接的协议,所以使用TCP前必须先建立连接,而建立连接是通过三次握手来进行的。具体过程如下图所示:

TCP三次握手

  • 一开始,客户端和服务端都处于CLOSE状态。先是服务端主动监听某个端口,处于LISTEN状态。

  • 第一次握手,客户端会随机初始化序号(client_isn),将该序号设置为TCP首部序列号字段,同时把SYN标志位置为1,表示客户端向服务端发起连接,该报文不包含数据,之后客户端处于SYN_SENT状态。

    第一次握手

  • 第二次握手,服务端接收到客户端发来的SYN报文,首先也会随机初始化自己的序列号(server_isn),将此序号设置到TCP首部序列号字段,接着把确认应答号字段设置为client_isn + 1,把SYNACK标志位设置为1。最后把报文发送给客户端,该报文也不包含数据,服务端进入SYN_RCVD状态。

    第二次握手

  • 第三次握手,客户端收到SYN+ACK报文后,向服务端发送一个应答报文,将确认应答号设置为server_isn + 1ACK标志位也设置为1,最后把报文发送给客户端,此次报文可以包含数据,发送后客户端处于ESTABLISHED状态。

    第三次握手

  • 服务端收到报文后,也进入ESTABLISHED状态。

一旦完成三次握手,双方都处于ESTABLISHED状态,此时连接就已经建立完成,客户端和服务端就可以互相发送数据了。

2.2 为什么是三次握手,不是两次、四次

在前面,我们知道了什么是TCP连接:用于保证可靠性流量控制维护的某些状态信息,这些信息的组合称为连接。

接下来,以三个方面分析三次握手的原因:

  1. 三次握手才可以阻止重复历史连接的初始化(主要原因)
  2. 三次握手才可以同步双方的初始序列号
  3. 三次握手才可以避免资源浪费

2.2.1 避免历史连接

简单来说,三次握手的首要原因是为了防止旧的重复连接初始化造成混乱。

假设,客户端先发送了SYN(seq = 90)报文,然后客户端宕机了,而且这个SYN报文还被网络阻塞了,服务器并没有收到,接着客户端重启,又像服务端建立连接,发送SYN(seq = 100)报文(这里不是重传,重传的SYN序号是一样的)。

  • 一个旧SYN报文新SYN报文早到达了服务端,这时服务端会回一个SYN+ACK报文给客户端,此报文中的确认应答号是91(90 + 1)。

  • 客户端收到后,发现自己期望收到的确认应答号应该是101(100 + 1),而不是91,于是就会回RST报文。

  • 服务端收到RST报文后,就会释放连接。

  • 后续新的SYN报文抵达服务器后,客户端与服务端就可以正常的完成三次握手了。

    避免历史连接

上述的旧SYN报文成为历史连接,TCP使用三次握手建立连接的最主要原因就是防止历史连接初始化了连接,造成资源浪费。

TIPS:有人可能会问了,如果服务端在收到RST报文之前,就先收到了新SYN报文,这时会发生什么?

当服务端第一次收到SYN报文,也就是收到旧SYN报文时,就会回复SYN+ACK报文给客户端,此时报文中的确认应答号是91(90 + 1)。

然后这时再收到新SYN报文时,就会回Challenge ACK报文给客户端,这个ACK报文并不是确认收到新SYN报文的,而是上一次的ACK确认应答号91(90 + 1)。所以客户端收到此ACK报文时,发现与期望收到的确认应答号101(100 + 1)不符,于是会回RST报文。

如果时两次握手连接,就无法阻止历史连接,在两次握手的情况下,服务端没有中间状态给客户端来阻滞历史连接,导致服务器可能建立一个历史连接,造成资源浪费。

在两次握手的情况下,服务器收到SYN报文后,就进入ESTABLISHED状态,意味着这时可以给对方发送数据,但是客户端此时还没有进入ESTABLISHED状态,假设这次是历史连接,客户端判断到此次连接为历史连接,就会回RST报文来断开连接,而服务端在第一次握手时就进入了ESTABLISHED状态,所以它认为可以发送数据,但是它并不知道这是个历史连接,只有它收到RST报文后,才会断开连接。

两次握手

可以看到,如果两次握手建立TCP连接的场景下,服务端在向客户端发送数据前,并没有阻止掉历史连接,导致服务端建立了一个历史连接,不仅白白发送了数据,而且浪费了服务器的资源。

所以,TCP三次握手建立连接的主要原因就是防止历史连接初始化了连接。

2.2.2 同步双方初始序列号

TCP协议的通信双方,都必须维护一个序列号,序列号是TCP可靠传输的一个关键因素。

  • 接收方可以去除重复的数据
  • 接收方可以根据数据包的序列号按顺序接收
  • 可以标识发出去的数据包中,哪些是已经被对方收到的(通过ACK报文中的应答序列号知道)

可见,序列号在TCP连接中占据着非常重要的作用,所以当客户端发送携带初始序列号的SYN报文时,需要服务端回一个ACK应答报文,表示客户端的SYN报文已经被服务端成功接收,当服务端发送的初始序列号给客户端时,依然也要得到客户端的回应,这样一来一回,才能确保双方的初始序列号能被可靠的同步。

四次握手和三次握手

四次握手也能够可靠的同步双方的初始化序列号,由于第二步和第三步可以优化成一步,所以就成了三次握手

而两次握手只保证了一方的初始序列号能被对方成功接收,没办法保证双方的初始序列号都能被确认接收。

2.2.3 避免资源浪费

如果只有两次握手,当客户端发送的SYN报文在网络中阻塞,客户端没有接收到ACK报文,就会重新发送SYN,由于没有第三次握手,服务器不清楚客户端是否收到了字节回复的ACK报文,所以服务端每收到一个SYN就只能先主动建立一个连接,如果客户端大宋的SYN报文在网络中阻塞了,重复发送多次SYN报文,那么服务端在收到请求后就会建立多个冗余的无效连接,造成不必要的资源浪费。

两次握手

总结

TCP建立连接时,通过三次握手就能防止历史连接的建立,帮助双方同步初始序列号,减少双方不必要的资源开销。保证TCP连接的可靠性。

不使用两次握手和四次握手的原因:

  • 两次握手:无法防止历史连接的建立,会造成双方资源的浪费,也无法可靠的同步双方初始序列号
  • 四次握手:三次握手就已经理论上最少可靠连接建立,不需要更多的通信次数。

3. TCP连接断开

3.1 四次挥手的过程

天下没有不散的宴席,对于TCP连接也是这样。TCP连接断开是通过四次挥手方式。

双方都可以主动断开连接,断开连接后主机的资源将被释放,四次挥手过程如下图所示:

客户端主动关闭连接 —— TCP 四次挥手

  • 客户端打算关闭连接,此时会发送一个TCP首部FIN标志位被置为1的报文,之后客户端进入FIN_WAIT_1状态。
  • 服务端收到FIN报文后,就向客户端发送ACK应答报文,接着服务器进入CLOSE_WAIT状态。
  • 客户端收到ACK应答报文后,进入FIN_WAIT_2状态。
  • 等待服务端处理完数据后,也想客户端发送FIN报文,之后服务端进入LAST_ACK状态。
  • 客户端收到FIN报文后,回复一个ACK应答报文,之后进入TIME_WAIT状态。
  • 服务端收到ACK应答报文后,就进入CLOSE状态,至此服务端已经完成连接的关闭。
  • 客户端在经过2MSL一段时间后,自动进入CLSOE状态,至此客户端也完成连接的关闭。

每个方向都需要一个FIN和一个ACK,因此通常被称为四次挥手。

这里需要注意的是:主动关闭连接的,才有TIME_WAIT状态

3.2 为什么挥手需要四次

再来回顾一下四次挥手双方发FIN包的过程,就能理解为什么需要四次了。

  • 关闭连接时,客户端向服务端发送FIN报文时,仅仅表示客户端不再发送数据了,但是还能接收数据。
  • 服务端收到客户端的FIN报文时,先回一个ACK应答报文,而服务端可能还有数据需要处理和发送,等服务端不再发送数据时,才发送FIN报文给客户端表示同意关闭连接。

从上面过程可知,服务端通畅需要等待完成数据的发送和处理,所以服务端的ACKFIN一般会分开发送,因此是需要四次挥手。

但是在特定情况下,四次挥手是可以变成三次挥手的

3.3 什么情况会出现三次挥手

当被动关闭方(这里是服务端)在TCP挥手过程中,没有数据要发送并且开启了TCP延迟确认机制,那么第二次和第三次挥手就会合并发送,这样就出现了三次挥手。

三次挥手

什么是延迟确认机制?

当发送没有携带数据的ACK报文时,它的网络效率是很低的,因为它也有40个字节的IP首部和TCP首部,但却没有携带数据报文。为了解决ACK传输效率低的问题,就衍生出了TCP延迟确认。TCP延迟确认的具体策略如下:

  • 当有响应数据要发送时,ACK会随着响应数据一起立刻发送给对端。
  • 当没有响应数据要发送时,ACK将会延迟一段时间,等待是否有响应数据可以一起发送。
  • 如果在延迟等待发送ACK期间,对方的第二个数据报文又到达了,这时会立刻发送ACK

TCP延迟确认

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/997227.html

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

相关文章

【javaweb课设源码】图书管理系统SSM Mysql 期末课设

文章目录 简介 简介 本系统使用Javaweb技术制作,数据库为mysql 附带论文报告文档 printf("需要源码,可以baidu学长敲代码");

input子系统框架、外设驱动开发

一、input子系统基本框架 Linux内核为了两个目的: 简化纯输入类外设(如:键盘、鼠标、游戏杆、轨迹球、触摸屏。。。等等)的驱动开发统一输入类外设产生的数据格式(struct input_event),更加方…

【LeetCode题目详解】第九章 动态规划part10 121. 买卖股票的最佳时机 122.买卖股票的最佳时机II (day49补)

本文章代码以c为例! 股票问题是一个动态规划的系列问题 一、力扣第121题:买卖股票的最佳时机 题目: 给定一个数组 prices ,它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。 你只能选择 某一天 买入这只股票&#x…

Android学习之路(14) AMS与PMS详解

Android 系统启动流程与 Zygote、SystemServer 在讲解 Zygote 之前,考虑到不同的系统版本源码都不相同,以下分析的源码基于 Android 8.0.0。 init 进程 当系统启动时,init 进程是继 Linux 内核启动后第二个启动的进程,它是在用…

AOP代理中Cglib使用场景

有接口时会使用JDK动态代理 没有接口实现类的情况下使用Cglib进行动态代理

layui手机端使用laydate时间选择器被输入法遮挡的解决方案

在HTML中,你可以使用input元素的readonly属性来禁止用户输入,但是这将完全禁用输入,而不仅仅是禁止弹出输入法。如果你想允许用户在特定条件下输入,你可以使用JavaScript来动态地切换readonly属性。 readonly属性 增加readonly属…

【iOS】MVC

文章目录 前言一、MVC各层职责1.1、controller层1.2、model层1.3、view层 二、总结三、优缺点3.1、优点3.2、缺点 四、代码示例 前言 MVC模式的目的是实现一种动态的程序设计,使后续对程序的修改和扩展简化,并且使程序某一部分的重复利用成为可能。除此…

【交叉熵损失torch.nn.CrossEntropyLoss详解-附代码实现】

CrossEntropyLoss 什么是交叉熵softmax损失计算验证CrossEntropyLoss 输入输出介绍验证代码 什么是交叉熵 交叉熵有很多文章介绍,此处不赘述。只需要知道它是可以衡量真实值和预测值之间的差距的,因而用交叉熵来计算损失的时候,损失是越小越…

【JavaScript手撕代码】new

目录 手写 手写 /* * param {Function} fn 构造函数 * return {*} **/ function myNew(fn, ...args){if(typeof fn ! function){return new TypeError(fn must be a function)}// 先创建一个对象let obj Object.create(fn.prototype)// 通过apply让this指向obj, 并调用执行构…

SHIB去零计划:创新金融未来,打造稳定数字资产新范式

SHIB去零计划,由星火有限公司发起,以区块链去中心化手段解决信任危机,对抗垄断与不公平问题,破解经济制裁,实现稳定数字资产的快速有效、平等互利交易。星火有限公司,一家跨国运营集团,主营业务…

UIStackView入门使用两个问题

项目中横向一排元素,竖向一排元素,可以使用UIStackView。UIStackView的原理不做介绍,这里主要讲两个初次使用容易出现的两个问题。 首先创建一个stackview -(UIStackView*)titleStackView{if(_titleStackView nil){_titleStackView [UISta…

时序分解 | MATLAB实现北方苍鹰优化算法NGO优化VMD信号分量可视化

时序分解 | MATLAB实现北方苍鹰优化算法NGO优化VMD信号分量可视化 目录 时序分解 | MATLAB实现北方苍鹰优化算法NGO优化VMD信号分量可视化效果一览基本介绍程序设计参考资料 效果一览 基本介绍 北方苍鹰优化算法NGO优化VMD,对其分解层数,惩罚因子数做优化…

绝对的搜索利器

苏生不惑第450 篇原创文章,将本公众号设为星标,第一时间看最新文章。 今天分享几个文件搜索利器,下载地址在公众号苏生不惑后台回复2023909,你的小电影要藏不住了。 首先自然是Everything https://www.voidtools.com/zh-cn/&#…

python DVWAXSSPOC练习

XSS反射性低难度 数据包 GET /dv/vulnerabilities/xss_r/?name%3Cscript%3Ealert%28%27xss%27%29%3C%2Fscript%3E HTTP/1.1Host: 10.9.75.161Upgrade-Insecure-Requests: 1User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Ch…

数据结构与算法-BtreeB+Tree

一:引入 作为一个IT从业者大家对数据库肯定是都知道的,大家应该知道在数据库中有个索引,在一张表中用了索引与不用索引那查找效率简直就是天壤之别,但是大家有没思考过,你经常用的索引是什么样的数据结构呢&#xff1f…

Unity中Shader抓取屏幕并实现扭曲效果

文章目录 前言一、屏幕抓取,在上一篇文章已经写了二、实现抓取后的屏幕扭曲实现思路:1、屏幕扭曲要借助传入 UV 贴图进行扭曲2、传入贴图后在顶点着色器的输入参数处,传入一个 float2 uv : TEXCOORD,用于之后对扭曲贴图进行采样3、…

SAP 创建动态内表

创建动态内表 一、根据表名创建内表 程序代码: "复杂方式 SELECTION-SCREEN BEGIN OF BLOCK b1 WITH FRAME TITLE TEXT-001. PARAMETERS:p_tab TYPE string. SELECTION-SCREEN END OF BLOCK b1.DATA:lr_struct TYPE REF TO data,lr_table TYPE REF TO data. …

【云原生系列】Docker学习

目录 一、Docker常用命令 1 基础命令 2 镜像命令 2.1 docker images 查看本地主机的所有镜像 2.2 docker search 搜索镜像 2.3 docker pull 镜像名[:tag] 下载镜像 2.4 docker rmi 删除镜像 2.5 docker build 构建镜像 3 容器命令 3.1 如拉取一个centos镜像 3.2 运行…

.env文件详解

.env配置文件 vue会根据 process.env.NODE_ENV 的值,自动加载对应的环境配置文件 .env 全局默认配置文件,在所有的环境中被载入;.env.production 生产环境文件 production;.env.development 开发环境文件 development;.env.test/.env.stagi…

从零开始完整实现-循环神经网络RNN

一 简介 使用 pytorch 搭建循环神经网络RNN,循环神经网络(Recurrent Neural Network,RNN)是一类用于 处理序列数据的神经网络架构。与传统神经网络不同,RNN 具有内部循环结构,可以在处理序列数据时保持状态…