文章目录
三次握手和四次挥手简述
三次握手,即客户端与服务端进行的三次通信。四次挥手,就是客户端和服务端通过四次通信释放连接,也叫连接终止协议。
三次握手的目的
三次握手是为了让客户端和服务端分别确认自己和对方接收和发送消息的能力是正常的。
三次握手流程详解
序号 | 报文路径 | 客户端状态 | 报文信息 | 服务器状态 | 目的 |
---|---|---|---|---|---|
第一次握手 | C->S | SYN_SENT | SYN=1,seq=x | LISTEN |
C:自己发信息正常 S:自己收信息正常,C发消息正常 |
第二次握手 | S->C | SYN_SENT |
SYN=1,ACK=1, seq=y,ack=x+1 |
SYN_RCVD |
C:自己收信息正常,S收发信息正常 S: 自己发消息正常,但 S不知道C收消息是否正常 ->需要第三次握手 |
第三次握手 | C->S | ESTABLISHED | ACK=1,seq=x+1,ack=y+1 | ESTABLISHED | S:C接收信息正常 |
-
初始时:客户端处于
Closed
状态,服务器处于
Listen
状态; -
第一次握手
:客户端发送
SYN报文
给服务器,初始序列号为x(seq=x), 此时
客户端进入SYN_SENT状态
;这时,客户端可以知道自己发送能力正常,服务器可以知道自己接收能力正常,客户端发送能力正常。 -
第二次握手
:服务器通过自己的SYN报文给与客户端
确认和响应
,服务器进入
SYN_RECV
状态;这时
客户端可以知道服务器收发能力正常,自己收发能力正常;服务器知道自己收发能力正常,但不知道客户端接收能力正常,因此需要第三次握手
。服务器发送报文的四个参数具体含义如下:-
SYN=1
,表示为连接请求报文,也不能携带数据; -
seq=y
,服务端的序列号为y; -
ACK=1
,表示确认客户端序列号有效,此时确认号(ack)有值; -
ack=seq+1
:ack的值为客户端传来的序列号(seq)加1,即ack=x+1;
-
-
第三次握手
:客户端收到服务器的SYN+ACK的包,此时客户端处于
ESTABLISHED
(已确认)状态,表示客户端和服务器都表示同意连接,因此客户端发送一个
ACK报文
,ack仍为序列号+1,即y+1,初始序列号为x,因此客户端发送的第二次报文,序列号要+1,即x+1;这时服务器可以确认客户端收发能力正常;
第三次握手可以携带数据
。
- SYN=1或ACK=1表明这是一个连接请求报文
SYN=1时的报文不能携带数据
,如果可以携带数据的话,如果有人在第一次握手的SYN报文放入很多数据,重复发送大量的这些报文,服务器就会消耗大量内存缓存这些报文,服务器就更容易被攻击。
半连接队列和全连接队列
完成第一次和第二次握手后的TCP连接,讲socket放到半连接队列中;
完成第三次握手后,socket会从半连接队列移到全连接队列,当调用
accpet
函数时,从全连接队列中返回可用的socket给用户进程。
四次挥手的目的
TCP是全双工的工作模式,因此
每个方向都必须单独进行关闭
。当一方完成自己的数据发送任务后,就可以发送一个FIN报文来终止这个方向的连接。
全双工
:客户端在给服务器端发送消息的同时,服务器端也可以给客户端发送消息;
半双工
:客户端可以给服务端发消息,服务器端也可以给客户端发消息,但客户端和服务端不能同时发。
四次挥手详解
- 刚开始客户端和服务器端都处于ESTABLISHED状态,假如客户端发起关闭请求;
-
第一次挥手
:客户端向服务器发送FIN报文(FIN=1,seq=u),发完后进入
FIN_WAIT_1
状态,即主动关闭TCP连接,
不再发送数据,但可以接收服务器发来的报文
,等待服务器回复; -
第二次挥手
:服务器接到FIN报文后,返回一个ACK报文(ACK=1,ack=u+1,seq=v),表明自己接收到此报文,服务器进入
CLOSE_WAIT
关闭等待状态,此时客户端就知道服务端接到自己的断开连接请求,进入到
FIN_WAIT_2
状态,TCP处于
半关闭
状态,但服务器端可能还有数据要传输。 -
第三次挥手
:服务器关闭客户端连接,发送FIN报文(FIN=1,seq=w,ack=u+1)给客户端,此时服务器处于
LAST_ACK
状态,等待客户端回应。 -
第四次挥手
:客户端收到FIN报文后,发送一个ACK(ACK=1,ack=w+1,seq=u+1)给服务器作为应答,此时客户端处于
TIME_WAIT
状态,
这个状态是为了等待足够的时间以确保TCP接收到连接中断请求的确认
。 -
注意
:这时服务器到客户端的TCP连接并未被释放,客户端需要经过等待
2MSL
(MSL表示一个报文的来回时间)后才会进入
CLOSED
状态,这样做的目的是确保服务器收到自己的ACK报文,如果在规定时间没有收到客户端发的ACK,那么服务器会重发FIN,客户端再次收到FIN报文,就知道自己的ACK丢了,然后会重发ACK给服务器。服务器收到ACK后,就会关闭连接,处于CLOSE状态了。 -
等待2MSL的原因
:
- 防⽌客户端最后⼀次发给服务器的确认在⽹络中丢失以⾄于客户端关闭,⽽服务端并未关闭,导致资源的浪费。
- 等待最⼤的2msl可以让本次连接的所有的⽹络包在链路上消失,以防造成不必要的⼲扰。
如果客户端直接closed,然后⼜向服务端发起了⼀个新连接,我们不能保证这个新连接和刚关闭的连接的端⼝号是不同的。假设新连接和已经关闭的⽼端⼝号是⼀样的,如果前⼀次滞留的某些数据仍然在⽹络中,这些延迟数据会在新连接建⽴后到达服务端,所以socket就认为那个延迟的数据是属于新连接的,数据包就会发⽣混淆。所以客户端要在TIME_WAIT状态等待2倍的MSL,这样保证本次连接的所有数据都从⽹络中消失。
序号 | 报文路径 | 客户端状态 | 报文信息 | 服务器状态 |
---|---|---|---|---|
第一次挥手 | C->S | FIN_WAIT_1 | FIN=1,seq=u | ESTABLISHED |
第二次挥手 | S->C | FIN_WAIT_2 | ACK=1,seq=v,ack=u+1 | CLOSE_WAIT |
第三次挥手 | S->C | FIN_WAIT_2 | FIN=1,seq=v,ack=u+1 | LAST_ACK |
第四次挥手 | C->S | TIME_WAIT | ACK=1,ack=w+1,seq=u+1 | CLOSED |
为什么客户端需要TIME_WAIT状态
假设最终的ACK丢失,服务器会重发FIN,客户端必须维护TCP状态信息以便可以重发最终的ACK,否则就发送RST(TCP连接出错),结果服务端认为发生错误。
TCP实现必须可靠地终止连接的两个方向(全双工关闭),客户端必须进入TIME_WAIT状态,以免可能出现重发ACK的情形
。
为什么挥手比握手多一次
因为握手的时候并没有数据传输,所以服务端的** SYN 和 ACK 报文可以一起发送**,但是挥手的时候有数据在传输,所以
ACK 和 FIN报文不能同时发送
,需要分两步,所以会比握手多一步。
为什么三次挥手不行
因为服务端在接收到FIN, 往往
不会立即返回FIN
,必须等到服务端所有的报文都发送完毕了,才能发FIN。因此
先发一个ACK表示已经收到客户端的FIN
,延迟一段时间才发FIN。这就造成了四次挥手。
如果是三次挥手会造成:
如果将服务端的两次挥手合为一次,等于说服务端将ACK和FIN的发送合并为一次挥手,这个时候
长时间的延迟
可能会导致客户端误以为FIN没有到达客户端,
从而让客户端不断的重发FIN
。所有只能第二次握手先发送ACK确认接收到了客户端的数据,等服务器发送完了数据,再发送FIN包进行第三次挥手。
TCP报文参数释义
在三次握手和四次挥手中,报文发送都会携带一些参数,这些参数的具体解释如下:
-
SYN
:同步序列号标志位,tcp三次握⼿中,第⼀次会将SYN=1,ACK=0,此时表⽰这是⼀个连接请求报⽂段,对⽅会将SYN=1,ACK=1,表⽰同意连接,连接完成之后将SYN=0 -
FIN
:在tcp四次挥⼿时第⼀次将FIN=1,表⽰此报⽂段的发送⽅数据已经发送完毕,这是⼀个释放链接的标志 -
ACK
:当ACK=1时,我们的确认序列号ack才有效,当ACK=0时,确认序号ack⽆效,TCP规定:所有建⽴连接的ACK必须全部置为1 -
序号(seq)
:占 32位4 个字节,序号范围[0,2^32-1],序号增加到 2^32-1 后,下个序号又回到 0。TCP 是面向字节流的,通过 TCP 传送的字节流中的每个字节都按顺序编号,而报头中的序号字段值则指的是本报文段数据的第一个字节的序号。例如:我们的seq = 201,携带的数据有100,那么最后⼀个字节的序号就为300,那么下⼀个报⽂段就应该从301开始. -
确认号(ack)
:占 32位4 个字节,期望收到对方下个报文段的第一个数据字节的序号。当标志位ACK值为1时,才能产生有效的确认号ack。并且:ack=seq+1; -
RST
:当RST=1时,表明TCP连接出现严重错误,此时必须释放连接,之后重新连接,⼜叫重置位. -
URG
:紧急指针标志位,当URG=1时,表明紧急指针字段有效.它告诉系统中有紧急数据,应当尽快传送,这时不会按照原来的排队序列来传送.⽽会将紧急数据插⼊到本报⽂段数据的最前⾯ -
PSH
:推送操作,提示接收端应用程序立即从TCP缓冲区把数据读走
ACK、SYN和FIN这些大写的单词表示标志位,其值要么是1,要么是0;ack、seq小写的单词表示序号