TCP三次握手与四次挥手(详解)

article/2025/9/23 1:02:28

TCP三次握手

一:引出


客户端与服务器之间数据的发送和返回的过程当中需要创建一个叫TCP connection的东西;由于TCP不存在连接的概念,只存在请求和响应,请求和响应都是数据包,它们之间都是经过由TCP创建的一个从客户端发起,服务器接收的类似连接的通道,这个连接可以一直保持,http请求是在这个连接的基础上发送的;在一个TCP的连接上是可以发送多个http请求的

二:TCP的报文格式


1:TCP在传输层和网络层数据传输的过程
TCP协议是在传输层端到端的传输信息,既然说到传输层协议,那么就讲一下传输层协议在数据传输过程中的位置:


左边家庭要给右边家庭通信中的(应用层和传输层和网络层)
左边家庭的孩子小红(应用层中 应用进程)写了一封信(应用消息),然后小红将信交给了哥哥李雷(传输层),李雷将信放入到家门口的信箱里,邮递员来了将信取走放到了邮政汽车上,然后邮政汽车肯定不是直达的,他们到了转运中心(路由器)转到另一辆汽车上根据时间成本,路线成本等选择一条路继续运输(网络层)。

2:TCP报文

其中比较重要的字段

a:序号(sequence number):
Seq序号,占32位,用来标识从TCP源端向目的端发送的字节流,发起方发送数据时对此进行标记。

对序号的补充:
应用层向TCP层发送用于网间传输的、用8位字节表示的数据流,然后TCP把数据流分区成适当长度的 报文段 (通常受该计算机连接的网络的 数据链路层 的 最大传输单元 ( MTU )的限制)。之后TCP把结果包传给IP层,由它来通过网络将包传送给接收端实体的TCP层**。TCP为了保证不发生丢包,就给每个包一个序号,同时序号也保证了传送到接收端实体的包的按序接收。**然后接收端实体对已成功收到的包发回一个相应的确认( ACK );如果发送端实体在合理的往返时延(RTT)内未收到确认,那么对应的数据包就被假设为已丢失将会被进行重传。TCP用一个 校验和 函数来检验数据是否有错误;在发送和接收时都要计算校验和。

b:确认序号(acknowledgement number):
Ack序号,占32位,只有ACK标志位为1时,确认序号字段才有效,Ack=Seq+1。

c:标志位(Flags):
共6个,即URG、ACK、PSH、RST、SYN、FIN等。具体含义如下
URG:紧急指针(urgent pointer)有效。
ACK:确认序号有效,确认接收到消息;
PSH:接收方应该尽快将这个报文交给应用层。
RST:重置连接。
SYN:发起一个新连接。
FIN:释放一个连接。

三:TCP的三次握手的图示


1:图示


所谓的三次握手即TCP连接的建立。这个连接必须是一方主动打开,另一方被动打开的。
以下为客户端主动发起连接的图解:


2:客户端各个状态:


CLOSED状态:为关闭状态
SYN_SENT状态:为请求连接状态, 当你要访问其它的计算机的服务时首先要发个同步信号给该端口,此时状态为SYN_SENT,如果连接成功了就变为ESTABLISHED,此时SYN_SENT状态非常短暂。
ESTABLISHED状态:连接成功 

3:服务端的各个状态:


LISTENING状态:监听状态, State显示是LISTENING时表示处于侦听状态,就是说该端口是开放的,等待连接,但还没有被连接。就像你房子的门已经敞开的,但还没有人进来。
SYN-RCVD状态:收到和发送一个连接请求后等待对方对连接请求的确认。
ESTABLISHED状态:连接成功

补充:SYN-RCVD状态

  • 当服务器收到客户端发送的同步信号时,将标志位ACK和SYN置1发送给客户端,此时服务器端处于SYN_RCVD状态,
  • 如果连接成功了就变为ESTABLISHED,正常情况下SYN_RCVD状态非常短暂。如果发现有很多SYN_RCVD状态,那你的机器有可能被SYN Flood的DoS(拒绝服务攻击)攻击了。

SYN Flood的攻击原理是:
在进行三次握手时,攻击软件向被攻击的服务器发送SYN连接请求(握手的第一步),
但是这个地址是伪造的,如攻击软件随机伪造了51.133.163.104、65.158.99.152等等地址。
服务器 在收到连接请求时将标志位 ACK和 SYN 置1发送给客户端(握手的第二步),
但是这些客户端的IP地址都是伪造的,服务器根本找不到客户机,也就是说握手的第三步不可能
完成。这种情况下服务器端一般会重试(再次发送SYN+ACK给客户端)并等待一段时间后丢弃这个
未完成的连接,这段时间的长度我们称为SYN Timeout,一般来说这个时间是分钟的数量级
(大约为30秒-2分钟);一个用户出现异常导致服务器的一个线程等待1分钟并不是什么很大的问题,
但如果有一个恶意的攻击者大量模拟这种情况,服务器端将为了维护一个非常大的半连接列表而
消耗非常多的资源----数以万计的半连接,即使是简单的保存并遍历也会消耗非常多的
CPU 时间和内存,何况还要不断对这个列表中的IP进行SYN+ACK的重试。
此时从正常客户的角度看来,服务器失去响应,这种情况我们称做: 服务器端受到了
SYN Flood攻击(SYN洪水攻击 )

4:TCP三次握手的过程


握手之前主动打开连接的客户端结束CLOSED阶段,被动打开的服务器端也结束CLOSED阶段,并进入LISTEN阶段。随后开始“三次握手”:

a:首先客户端先向服务器端发送一个TCP报文

  • 标记位为SYN,表示“请求建立新连接”;
  • 序号为Seq=X(X一般为1)(传输信息的时候每个数据包的序号);
  • 随后客户端进入SYN-SENT阶段(请求连接的阶段)。

b:服务器端收到来自客户端的TCP报文之后,结束LISTEN阶段。并返回一段报文

  • 标志位为SYN和ACK,表示“确认客户端的报文Seq序号有效,服务器能正常接收客户端发送的数据,并同意创建新连接”(即告诉客户端,服务器收到了你的数据);
  • 序号为Seq=y;(返回一个收到信息的数据包 并给其标序号为y)
  • 确认号为Ack=x+1,表示收到客户端的序号Seq并将其值加1作为自己确认号Ack的值(两端配对 接收到消息 并反馈的过程;随后服务器端进入SYN-RCVD阶段。

ACK:代表确认收到消息

c:客户端接收到来自服务器确认收到数据的TCP报文后,明确了从客户端到服务器的数据传输是正常的,结束SYN-SENT阶段,并返回一段TCP报文

  • 标志位为ACK,表示“确认收到服务器端同意连接的信号”(即告诉服务器,我知道你收到我发的数据了);
  • 序号为Seq=x+1,表示收到服务器端的确认号Ack,并将其值作为自己的序号值;
  • 确认号为Ack=y+1,表示收到服务器端序号Seq,并将其值加1作为自己的确认号Ack的值;
  • 随后客户端进入ESTABLISHED阶段。(即成功建立了连接)

d:关于确认号Ack和数据包的序号Seq值得变化

  • Ack确认号:就是确认收到消息后 返回给 发送端的 序号(Ack = 发起方的Seq + 1) 即就是下次发送的端的seq序号。
    ACK确认序号(Seq)有效:确认发送的数据包的成功到达
  • Seq:序号:给每个数据包一个序号,保证接受端可以按序收到数据包(首次握手的时候 Seq = 上次握手的时候的Ack值,如果没有 则可以是任意值)
  • 在客户端与服务器端传输的TCP报文中,双方的确认号Ack和序号Seq的值,都是在彼此Ack和Seq值的基础上进行计算的,这样做保证了TCP报文传输的连贯性。一旦出现某一方发出的TCP报文丢失,便无法继续"握手",以此确保了"三次握手"的顺利完成

5:为甚要三次握手


a:为了防止服务器端开启一些无用的连接增加服务器开销

  • 第一次握手客户端发送的TCP报文,服务端成功接收;然后第二次握手,服务端返回一个确认收到消息的TCP报文,但这个报文因为某些原因丢失了,那么客户端就一直收不到这个TCP报文的。
  • 客户端设置了一个超时时间,超过了就重新发送一个TCP连接请求,那么如果没有第三次握手的话,服务端是不知道客户端是否收到服务返回的信息的,这样没有给服务器端一个创建还是关闭连接端口的请求,服务器端的端口就一直开着,等到客户端因超时重新发出请求时,服务器就会重新开启一个端口连接。那么服务器端上没有接收到请求数据的上一个端口就一直开着,长此以往,这样的端口多了,就会造成服务器端开销的严重浪费。

b:防止已失效的连接请求报文段突然又传送到了服务端,因而产生错误。

  • 已经失效的客户端发出的请求信息,由于某种原因传输到了服务器端,服务器端以为是客户端发出的有效请求,接收后产生错误。

c:总结

  • 也可以这样理解:“第三次握手”是客户端向服务器端发送数据,这个数据就是要告诉服务器,客户端有没有收到服务器“第二次握手”时传过去的数据。
  • 若发送的这个数据是“收到了”的信息,接收后服务器就正常建立TCP连接,否则建立TCP连接失败,服务器关闭连接端口。由此减少服务器开销和接收到失效请求发生的错误。(如果第三次握手失败的话,那服务端就关闭连接)

---------------------------------------------------------------------------------------------------------------------------------

TCP四次挥手(详解)

1:图示

在这里插入图片描述
二:TCP四次挥手的过程


所谓的四次挥手即TCP连接的释放(解除)。连接的释放必须是一方主动释放,另一方被动释放。挥手之前主动释放连接的客户端结束ESTABLISHED阶段。随后开始“四次挥手”:

a:首先客户端想要释放连接,向服务器端发送一段TCP报文,其中

  • 标记位为FIN,表示“请求释放连接“;
  • 序号为Seq=U;
  • 随后客户端进入FIN-WAIT-1阶段,即半关闭阶段。并且停止在客户端到服务器端方向上发送数据,但是客户端仍然能接收从服务器端传输过来的数据。

注意:这里不发送的是正常连接时传输的数据(非确认报文),而不是一切数据,所以客户端仍然能发送ACK确认报文。
b:服务器端接收到从客户端发出的TCP报文之后,确认了客户端想要释放连接,随后服务器端结束ESTABLISHED阶段,进入CLOSE-WAIT阶段(半关闭状态)并返回一段TCP报文,其中:

  • 标记位为ACK,表示“接收到客户端发送的释放连接的请求”;
  • 序号为Seq=V;
  • 确认号为Ack=U+1,表示是在收到客户端报文的基础上,将其序号Seq值加1作为本段报文确认号Ack的值;
  • 随后服务器端开始准备释放服务器端到客户端方向上的连接。
    客户端收到从服务器端发出的TCP报文之后,确认了服务器收到了客户端发出的释放连接请求,随后客户端结束FIN-WAIT-1阶段,进入FIN-WAIT-2阶段前"两次挥手"既让服务器端知道了客户端想要释放连接,也让客户端知道了服务器端了解了自己想要释放连接的请求。于是,可以确认关闭客户端到服务器端方向上的连接了

c:服务器端自从发出ACK确认报文之后,经过CLOSED-WAIT阶段,做好了释放服务器端到客户端方向上的连接准备,再次向客户端发出一段TCP报文,其中:
(第二次挥手 服务器端回复 确认收到 客户端想要释放连接的请求 返回ACK,但是 服务端还有些数据的处理,所以不能马上断开连接,所以需要第三次握手 即服务端发送 FIN 释放连接的标志位)

  • 标记位为FIN,ACK,表示“已经准备好释放连接了”。注意:这里的ACK并不是确认收到服务器端报文的确认报文。
  • 序号为Seq=W;
  • 确认号为Ack=U+1;表示是在收到客户端报文的基础上,将其序号Seq值加1作为本段报文确认号Ack的值。
    随后服务器端结束CLOSE-WAIT阶段,进入LAST-ACK阶段。并且停止在服务器端到客户端的方向上发送数据,但是服务器端仍然能够接收从客户端传输过来的数据。

d:客户端收到从服务器端发出的TCP报文,确认了服务器端已做好释放连接的准备,结束FIN-WAIT-2阶段,进入TIME-WAIT阶段,并向服务器端发送一段报文,其中:

  • 标记位为ACK,表示“接收到服务器准备好释放连接的信号”。
  • 序号为Seq=U+1;表示是在收到了服务器端报文的基础上,将其确认号Ack值作为本段报文序号的值。
  • 确认号为Ack=W+1;表示是在收到了服务器端报文的基础上,将其序号Seq值作为本段报文确认号的值。随后客户端开始在TIME-WAIT阶段等待2MSL。
    服务器端收到从客户端发出的TCP报文之后结束LAST-ACK阶段,进入CLOSED阶段。由此正式确认关闭服务器端到客户端方向上的连接。
    客户端等待完2MSL之后,结束TIME-WAIT阶段,进入CLOSED阶段,由此完成“四次挥手”。

e:总结
后“两次挥手”既让客户端知道了服务器端准备好释放连接了,也让服务器端知道了客户端了解了自己准备好释放连接了。于是,可以确认关闭服务器端到客户端方向上的连接了,由此完成“四次挥手”。

三:为什么握手是三次,挥手要四次?


a:握手三次(即在一次握手就可以搞定ACK+SYN)
TCP建立连接时之所以只需要"三次握手",是因为在第二次"握手"过程中,服务器端发送给客户端的TCP报文是以SYN与ACK作为标志位的。SYN是请求连接标志,表示服务器端同意建立连接;ACK是确认报文,表示告诉客户端,服务器端收到了它的请求报文。
即SYN建立连接报文与ACK确认接收报文是在同一次"握手"当中传输的,所以"三次握手"不多也不少,正好让双方明确彼此信息互通。

b:挥手四次
TCP释放连接时之所以需要“四次挥手”,是因为FIN释放连接报文与ACK确认接收报文是分别由第二次和第三次"握手"传输的。

b1:为何建立连接时一起传输,释放连接时却要分开传输?

  • 建立连接时,被动方服务器端结束CLOSED阶段进入“握手”阶段并不需要任何准备,可以直接返回SYN和ACK报文,开始建立连接。
  • 释放连接时,被动方服务器,突然收到主动方客户端释放连接的请求时并不能立即释放连接,因为还有必要的数据需要处理,所以服务器先返回ACK确认收到报文,经过CLOSE-WAIT阶段准备好释放连接之后,才能返回FIN释放连接报文。


四:为什么客户端在TIME-WAIT阶段要等2MSL?


为的是确认服务器端是否收到客户端发出的ACK确认报文

当客户端发出最后的ACK确认报文时,并不能确定服务器端能够收到该段报文。所以客户端在发送完ACK确认报文之后,会设置一个时长为2MSL的计时器。MSL指的是Maximum Segment Lifetime:一段TCP报文在传输过程中的最大生命周期。2MSL即是服务器端发出为FIN报文和客户端发出的ACK确认报文所能保持有效的最大时长。

  • 如果客户端在2MSL内,再次收到了来自服务器端的FIN报文,说明服务器端由于各种原因没有接收到客户端发出的ACK确认报文。客户端再次向服务器端发出ACK确认报文,计时器重置,重新开始2MSL的计时;
  • 否则客户端在2MSL内没有再次收到来自服务器端的FIN报文,说明服务器端正常接收了ACK确认报文,客户端可以进入CLOSED阶段,完成“四次挥手”。

http://chatgpt.dhexx.cn/article/h2V0gAPi.shtml

相关文章

TCP连接的四次挥手全过程

TCP通过四次挥手来释放连接 四次挥手的过程如下: 第一次挥手: 客户端向服务器发送一个 FIN 数据包(FIN 1,seq u)主动断开连接,报文中会指定一个序列号。告诉服务器:我要跟你断开连接了&am…

http三次握手四次挥手详解

1、 TCP的三次握手和四次挥手实质就是TCP通信的连接和断开。 三次握手:为了对每次发送的数据量进行跟踪与协商,确保数据段的发送和接收同步,根据所接收到的数据量而确认数据发送、接收完毕后何时撤消联系,并建立虚连接。 四次挥…

TCP四次挥手及原因

聚散终有时,TCP 断开连接是通过四次挥手方式。 双方都可以主动断开连接,断开连接后主机中的「资源」将被释放。 上图是客户端主动关闭连接 : 一次挥手 客户端打算关闭连接,此时会发送一个 TCP 首部 FIN 标志位被置为 1 的报文&…

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

文章目录 三次握手和四次挥手简述三次握手的目的三次握手流程详解半连接队列和全连接队列四次挥手的目的四次挥手详解为什么客户端需要TIME_WAIT状态为什么挥手比握手多一次为什么三次挥手不行TCP报文参数释义 三次握手和四次挥手简述 三次握手,即客户端与服务端进…

三次握手,四次挥手,为什么是三次握手四次挥手

三次握手 两次握手(情况1) 两次握手(情况2) OK,下面正经地来回答下这个问题,要搞清楚这个问题,首先得了解TCP究竟是如何保证可靠传输的。 PS:TCP协议中,主动发起请求的一…

TCP三次握手四次断开

转载地址:www.51niux.com IP协议是网络层的主要协议,为上层传输层提供无连接、无状态、不可靠的服务。优点是简单高效。无状态是指各个IP报文是独立传送的,不同步传输状态的信息,所以容易发生重复和乱序的情况。不可靠是指IP协议…

有关三次握手,四次挥手的超详细总结!!!

有关三次握手,四次挥手的超详细总结!!! 我们先来看一下三次握手和四次挥手的示意图: 图示为三次握手。 图示为四次挥手。 一、三次握手和四次挥手的过程: 三次握手: TCP建立连接的过程我们…

TCP四次挥手详解

在开始之前可以先了解一下 TCP三次握手 TCP四次挥手过程和状态变迁 为什么挥手需要四次? 为什么TIME_WAIT等待的时间是2MSL? 等待2MSL的意义 TIME_WAIT状态过多有什么危害? 如何解决TIME_WAIT状态过多? TCP四次挥手过程和…

C++ map遍历

C map遍历 #include <iostream> #include <map>using namespace std;int main() {map<int, int> _map;_map[0] 1;_map[1] 2;_map[10] 10;map<int, int>::iterator iter;iter _map.begin();while(iter ! _map.end()) {cout << iter->firs…

C++ map遍历(简单易记忆)

C中map遍历有两种方法&#xff1a; 第一种&#xff0c;使用迭代器&#xff0c;while循环 #include <iostream> #include <map> using namespace std; int main() {map<int,int> p;p[0] 1;p[1] 2;p[3] 4;map<int,int>::iterator it p.begin();whi…

Java中Map的4种遍历方式

原标题&#xff1a;Java中Map的4种遍历方式 第一种方式&#xff1a;这是平常用的最多也最可取的一种遍历方式。 for (Map.Entry entry : map.entrySet()) { System.out.println(“key” entry.getKey() “,value” entry.getValue()); 第二种方式&#xff1a;如果只需要…

HashMap的几种遍历方式及循环删除

目录 1. 前言2. HashMap 的遍历方式2.1. 迭代器 EntrySet2.2. 迭代器 KeySet2.3. ForEach EntrySet2.4. ForEach KeySet2.5. Lambda 表达式2.6. Streams API 3. 循环删除3.1. 迭代器 Iterator 方式3.2. ForEach 循环方式3.3. Lambda 表达式3.3.1. Lambda 删除的正确方式 3.4. S…

Map遍历四种方式及其效率

目录 1、Map介绍 2、Map数据结构及扩容 2.1、数组&#xff1a;寻址容易&#xff0c;插入和删除元素困难 2.2、链表&#xff1a;寻址困难&#xff0c;插入和删除元素容易 2.3、Map数组长度默认16&#xff0c;扩容负载因子为0.75 3、Map遍历4种方式及其效率 3.1、方式一&a…

前端map循环遍历使用

map定义 Array.map() ⽅法返回⼀个新数组&#xff0c;数组中的元素为原始数组元素调⽤函数处理后的值&#xff0c;同时不会改变原来的数组 var newArra[1,3,6,10,44]; var newArraysnewArra.map((index) > { return index*index }) console.log(newArra); //[1,3,6,10,44]…

map forEach for in 循环遍历

1.map遍历数组对象 var map [{ key : "百度", value : "李彦宏" },{key : "阿里巴巴", value : "马云" },]; for (var key in map) { console.log(map[key]); } 2.forEach遍历数组 forEach()方法需要一个函数作为参数&…

Map的循环遍历,修改,删除

预制数据 Map<String, String> map new HashMap<>();map.put("aaa","123");map.put("bbb","123");map.put("CCC","123"); 只循环key ---> map.keyset() for (String key : map.keySet()) {Syst…

Java遍历Map五种方法

一、Map集合遍历日常开发最常使用&#xff0c;简单总结五种方法差异。 ①、IteratorentrySet写法【推荐JDK8以下】&#xff0c;Map.Entry是Map接口的内部接口&#xff0c;获取迭代器&#xff0c;然后依次取出每个迭代器里面的Map.Entry Iterator<Map.Entry<Integer,Strin…

443端口被占用怎么办

前段时间配置SDN的时候装了虚拟机&#xff0c;然后最近打开Steam插件访问社区的时候发现跳出错误&#xff0c;443端口被占用&#xff0c;一脸懵逼&#xff0c;后来查找资料才发现原来是虚拟机的vmware-hosted进程占用了443端口 可以通过右键计算机——服务和应用程序——服务—…

当443端口被占用时如何解决?

有时候我们的一些软件需要443端口才能运行&#xff0c;但是443被占用了&#xff0c;应当怎么结束呢&#xff1f; 1&#xff0c;打开CMD&#xff0c;输入netstat -ano回车&#xff0c;如图&#xff1a; 可以看到某程序正在占用443端口&#xff08;左边一列0.0.0.0:443,0.0.0.0代…

steamcom启动服务:443端口被占用,请关闭占用该端口的进程后再点击启动服务!

steamcom启动服务&#xff1a;443端口被占用&#xff0c;请关闭占用该端口的进程后再点击启动服务! 最近想玩玩游戏放松放松&#xff0c;但是steam有点问题&#xff0c;于是下了个插件steamcom,但在启动服务时出现了错误。 过程结果及解决方案 1、下载压缩文件并解压 2、运…