三次握手
- 第一次握手:客户端向服务器发送一个 SYN 包,其中 SYN 标志位被设置为 1,表示客户端请求建立连接,并随机生成一个初始序列号 seq=x 。此时客户端进入 SYN_SENT 状态,等待服务器的确认1.
- 第二次握手:服务器收到客户端的 SYN 包后,必须确认客户端的 SYN,于是向客户端发送一个 SYN+ACK 包,SYN 和 ACK 标志位都被设置为 1 。服务器也会随机生成一个自己的初始序列号 seq=y ,同时将确认号 ack 设置为 x+1,表示已经收到了客户端的序列号为 x 的 SYN 包。此时服务器进入 SYN_RECV 状态1.
- 第三次握手:客户端收到服务器的 SYN+ACK 包后,会向服务器发送一个 ACK 包,ACK 标志位为 1,确认号 ack=y+1,表示已经收到了服务器的序列号为 y 的 SYN 包,而序列号 seq 则为 x+1 。发送完这个 ACK 包后,客户端和服务器都进入 ESTABLISHED 状态,此时 TCP 连接就成功建立了1.
四次挥手
- 第一次挥手:当客户端或服务器中的一方完成数据传输任务后,会发送一个 FIN 包给对方,表示自己不再发送数据了,希望关闭连接。例如客户端发送 FIN 包,此时客户端进入 FIN_WAIT_1 状态1.
- 第二次挥手:对方收到 FIN 包后,会发送一个 ACK 包给发送 FIN 包的一方,确认号为收到的 FIN 包的序列号加 1,表示已经收到了对方的关闭请求。比如服务器收到客户端的 FIN 包后,向客户端发送 ACK 包,服务器进入 CLOSE_WAIT 状态,而客户端收到 ACK 包后进入 FIN_WAIT_2 状态1.
- 第三次挥手:在发送完 ACK 包后,如果接收 FIN 包的一方也没有数据要发送了,它会发送一个 FIN 包给对方,表示自己也准备关闭连接。例如服务器在确认客户端的 FIN 包后,若自己也无数据可发,就会向客户端发送 FIN 包,此时服务器进入 LAST_ACK 状态1.
- 第四次挥手:客户端收到服务器的 FIN 包后,会再次发送一个 ACK 包给服务器,确认号为收到的 FIN 包的序列号加 1。客户端发送完 ACK 包后进入 TIME_WAIT 状态,等待一段时间后才会进入 CLOSED 状态,而服务器收到 ACK 包后直接进入 CLOSED 状态,至此 TCP 连接彻底关闭1
作用
- 三次握手的作用
- 建立连接的可靠性保障:通过三次握手,客户端和服务器之间能够相互确认对方具有收发数据的能力。第一次握手,客户端发起连接请求;第二次握手,服务器回应客户端,表明自己能够接收客户端请求并且也有发送数据的能力;第三次握手,客户端确认服务器的回应,双方都清楚对方已准备好进行数据传输,从而建立起可靠的连接基础,避免了无效连接的建立。
- 序列号同步:在握手过程中,双方交换初始序列号。序列号在后续的数据传输中用于对数据进行排序、确认和重传等操作,保证数据的顺序性和完整性。这使得接收方能够按照正确的顺序重组数据,同时也为可靠的数据传输机制提供了重要的标识。
- 防止旧连接的干扰:序列号的使用和三次握手的过程可以防止网络中延迟的旧数据包干扰新建立的连接。因为每一次新的连接都有新的序列号,接收方可以根据序列号来判断数据包是否属于当前连接,避免将过期的数据误认为是新连接中的有效数据。
- 四次挥手的作用
- 有序关闭连接:四次挥手是一种比较谨慎的连接关闭方式。双方通过发送 FIN 和 ACK 包来逐步关闭连接,确保数据能够完整地传输完毕并且双方都同意关闭连接。第一次挥手是一方主动提出关闭数据发送通道;第二次挥手是另一方对这个请求的确认,表示已经收到关闭请求;第三次挥手是另一方在自己也完成数据发送后,提出关闭自己的数据发送通道;第四次挥手是最初提出关闭请求的一方确认对方的关闭请求,从而实现双向的数据发送通道的有序关闭。
- 确保数据完整性:在挥手过程中,通过 ACK 包的确认机制,保证了在关闭连接之前,所有已经发送的数据都被正确接收。例如,在 CLOSE_WAIT 状态下,服务器可以继续发送未发送完的数据,直到全部发送完成后才发送 FIN 包关闭连接,这样可以避免数据丢失,确保数据的完整性。
- 资源释放:通过有序的四次挥手,双方能够合理地释放连接占用的资源,如缓存区、端口号等。这对于网络资源的有效利用非常重要,避免资源的浪费和因资源占用导致的潜在问题,如端口耗尽等情况。
TCP 三次握手过程是怎样的?
TCP 是面向连接的协议,所以使用 TCP 前必须先建立连接,而建立连接是通过三次握手来进行的。三次握手的过程如下图:
close,close,Listen,syn_sent,sys_rcvd,established,established
-
一开始,客户端和服务端都处于
CLOSE
状态。先是服务端主动监听某个端口,处于LISTEN
状态
-
客户端会随机初始化序号(
client_isn
),将此序号置于 TCP 首部的「序号」字段中,同时把SYN
标志位置为1
,表示SYN
报文。接着把第一个 SYN 报文发送给服务端,表示向服务端发起连接,该报文不包含应用层数据,之后客户端处于SYN-SENT
状态。
-
服务端收到客户端的
SYN
报文后,首先服务端也随机初始化自己的序号(server_isn
),将此序号填入 TCP 首部的「序号」字段中,其次把 TCP 首部的「确认应答号」字段填入client_isn + 1
, 接着把SYN
和ACK
标志位置为1
。最后把该报文发给客户端,该报文也不包含应用层数据,之后服务端处于SYN-RCVD
状态。
-
客户端收到服务端报文后,还要向服务端回应最后一个应答报文,首先该应答报文 TCP 首部
ACK
标志位置为1
,其次「确认应答号」字段填入server_isn + 1
,最后把报文发送给服务端,这次报文可以携带客户到服务端的数据,之后客户端处于ESTABLISHED
状态。 -
服务端收到客户端的应答报文后,也进入
ESTABLISHED
状态。
从上面的过程可以发现第三次握手是可以携带数据的,前两次握手是不可以携带数据的,这也是面试常问的题。
一旦完成三次握手,双方都处于 ESTABLISHED
状态,此时连接就已建立完成,客户端和服务端就可以相互发送数据了。
为什么是三次握手?不是两次、四次?
相信大家比较常回答的是:“因为三次握手才能保证双方具有接收和发送的能力。”
这回答是没问题,但这回答是片面的,并没有说出主要的原因。
在前面我们知道了什么是 TCP 连接:
-
用于保证可靠性和流量控制维护的某些状态信息,这些信息的组合,包括 Socket、序列号和窗口大小称为连接。
所以,重要的是为什么三次握手才可以初始化 Socket、序列号和窗口大小并建立 TCP 连接。
接下来,以三个方面分析三次握手的原因:
-
三次握手才可以阻止重复历史连接的初始化(主要原因)
-
三次握手才可以同步双方的初始序列号
-
三次握手才可以避免资源浪费
小结
TCP 建立连接时,通过三次握手能防止历史连接的建立,能减少双方不必要的资源开销,能帮助双方同步初始化序列号。序列号能够保证数据包不重复、不丢弃和按序传输。
不使用「两次握手」和「四次握手」的原因:
-
「两次握手」:无法防止历史连接的建立,会造成双方资源的浪费,也无法可靠的同步双方序列号;
-
「四次握手」:三次握手就已经理论上最少可靠连接建立,所以不需要使用更多的通信次数。
TCP 四次挥手过程是怎样的?
天下没有不散的宴席,对于 TCP 连接也是这样, TCP 断开连接是通过四次挥手方式。
双方都可以主动断开连接,断开连接后主机中的「资源」将被释放,四次挥手的过程如下图:
-
客户端打算关闭连接,此时会发送一个 TCP 首部
FIN
标志位被置为1
的报文,也即FIN
报文,之后客户端进入FIN_WAIT_1
状态。 -
服务端收到该报文后,就向客户端发送
ACK
应答报文,接着服务端进入CLOSE_WAIT
状态。 -
客户端收到服务端的
ACK
应答报文后,之后进入FIN_WAIT_2
状态。 -
等待服务端处理完数据后,也向客户端发送
FIN
报文,之后服务端进入LAST_ACK
状态。 -
客户端收到服务端的
FIN
报文后,回一个ACK
应答报文,之后进入TIME_WAIT
状态 -
服务端收到了
ACK
应答报文后,就进入了CLOSE
状态,至此服务端已经完成连接的关闭。 -
客户端在经过
2MSL
一段时间后,自动进入CLOSE
状态,至此客户端也完成连接的关闭。
你可以看到,每个方向都需要一个 FIN 和一个 ACK,因此通常被称为四次挥手。
这里一点需要注意是:主动关闭连接的,才有 TIME_WAIT 状态。
为什么挥手需要四次?
再来回顾下四次挥手双方发 FIN
包的过程,就能理解为什么需要四次了。
-
关闭连接时,客户端向服务端发送
FIN
时,仅仅表示客户端不再发送数据了但是还能接收数据。 -
服务端收到客户端的
FIN
报文时,先回一个ACK
应答报文,而服务端可能还有数据需要处理和发送,等服务端不再发送数据时,才发送FIN
报文给客户端来表示同意现在关闭连接。
从上面过程可知,服务端通常需要等待完成数据的发送和处理,所以服务端的 ACK
和 FIN
一般都会分开发送,因此是需要四次挥手。
但是在特定情况下,四次挥手是可以变成三次挥手的,具体情况可以看这篇:TCP 四次挥手,可以变成三次吗?(opens new window)
参考:
小林coding