文章目录
转自如下两篇文章:
TCP的三次握手与四次挥手理解及面试题(很全面)
面试官,不要再问我三次握手和四次挥手
每次看了TCP的三次握手和四次挥手,总是过一段时间就忘记了,写此文加深理解和记忆。
如下图所示,TCP首部中有很多信息,在这里我们需要关注的是 序号
,确认号
,ACK
, SYN
, FIN
等标志位
。
ISN(Initial Sequence Number)
:初始序列号。ACK(确认字符,Acknowledge Character)
:占1位,仅当ACK
=1时,确认号字段才有效。ACK
=0时,确认号无效。SYN(同步序列编号,Synchronize Sequence Numbers)
:是TCP/IP建立连接时使用的握手信号。当SYN
=1,ACK
=0时表示:这是一个连接请求报文段。若同意连接,则在响应报文段中使得SYN
=1,ACK
=1。因此,SYN
=1表示这是一个连接请求,或连接接受报文。SYN
这个标志位只有在TCP
建产连接时才会被置1,握手完成后SYN
标志位被置0。FIN
:用来释放一个连接。FIN=1表示:此报文段的发送方的数据已经发送完毕,并要求释放传输连接。- 序号
seq
:占4个字节,用来标记数据段的顺序,TCP
把连接中发送的所有数据字节都编上一个序号,第一个字节的编号(ISN
)由本地随机产生;给字节编上序号后,就给每一个报文段指派一个序号;序列号seq就是这个报文段中的第一个字节的数据编号。有了序号才知道传输的数据的顺序,在服务端才能正确组装信息。 - 确认号
ack
:占4个字节,期待收到对方下一个报文段的第一个数据字节的序号;确认号指的是期望接收到下一个字节的编号;因此当前报文段最后一个字节的编号+1即为确认号。
PS:ACK、SYN和FIN这些大写的单词表示标志位,其值要么是1,要么是0;ack、seq小写的单词表示序号。
下图表表示了各标志位的含义:
三次握手:
- 第一次握手:客户端给服务端发一个
SYN
报文,并指明客户端的初始化序列号ISN
。此时客户端处于SYN_SENT
状态。
首部的同步位SYN
=1,初始序号seq=x,SYN
=1的报文段不能携带数据,但要消耗掉一个序号。
- 第二次握手:服务器收到客户端的
SYN
报文之后,会以自己的SYN
报文作为应答,并且也指定了自己的初始化序列号ISN(s)
。同时会把客户端的ISN
+ 1 作为ACK
的值,表示自己已经收到了客户端的 SYN,此时服务器处于SYN_RCVD
的状态。这次握手实际做了两件事,一是告诉客户端收到了其SYN包,二是发送自己的SYN包来请求连接。
在确认报文段中SYN
=1,ACK
=1,确认号ack=x+1,初始序号seq=y。
- 第三次握手:客户端收到
SYN
报文之后,会发送一个ACK
报文,当然,也是一样把服务器的ISN
+ 1 作为ACK
的值,表示已经收到了服务端的SYN
报文,此时客户端处于ESTABLISHED
状态。服务器收到ACK
报文之后,也处于ESTABLISHED
状态,此时,双方已建立起了连接。
确认报文段ACK
=1,确认号ack=y+1,序号seq=x+1(初始为seq=x,第二个报文段所以要+1),ACK报文段可以携带数据,不携带数据则不消耗序号。
四次挥手:
- 第一次挥手:客户端发送一个
FIN
报文,报文中会指定一个序列号。此时客户端处于FIN_WAIT_1
状态。
即发出连接释放报文段(FIN
=1,序号seq=u),并停止再发送数据,主动关闭TCP
连接,进入FIN_WAIT_1(终止等待1)
状态,等待服务端的确认。 - 第二次挥手:服务端收到
FIN
之后,会发送ACK
报文,且把客户端的序列号值 +1 作为ACK
报文的序列号值,表明已经收到客户端的报文了,此时服务端处于CLOSE_WAIT
状态。即服务端收到连接释放报文段后即发出确认报文段(ACK
=1,确认号ack=u+1,序号seq=v),服务端进入CLOSE_WAIT(关闭等待)
状态,此时的TCP
处于半关闭状态,客户端到服务端的连接释放。客户端收到服务端的确认后,进入FIN_WAIT_2(终止等待2)
状态,等待服务端发出的连接释放报文段。 - 第三次挥手:如果服务端也想断开连接了,和客户端的第一次挥手一样,发给
FIN
报文,且指定一个序列号。此时服务端处于LAST_ACK
的状态。即服务端没有要向客户端发出的数据,服务端发出连接释放报文段(FIN
=1,ACK
=1,序号seq=w,确认号ack=u+1),服务端进入LAST_ACK(最后确认)
状态,等待客户端的确认。 - 第四次挥手:客户端收到
FIN
之后,一样发送一个ACK
报文作为应答,且把服务端的序列号值 +1 作为自己ACK
报文的序列号值,此时客户端处于TIME_WAIT
状态。需要过一阵子以确保服务端收到自己的ACK
报文之后才会进入CLOSED
状态,服务端收到ACK
报文之后,就处于关闭连接了,处于CLOSED
状态。
即客户端收到服务端的连接释放报文段后,对此发出确认报文段(ACK
=1,seq=u+1,ack=w+1),客户端进入TIME_WAIT(时间等待)
状态。此时TCP
未释放掉,需要经过时间等待计时器设置的时间2MSL
后,客户端才进入CLOSED
状态。
尝试回答下面的问题来确认是否真的理解了。
- 为什么需要三次握手,两次不行吗?
- 什么是半连接队列?
- ISN(Initial Sequence Number)是固定的吗?
- 三次握手过程中可以携带数据吗?
- SYN攻击是什么?
- 为什么连接的时候是三次握手,关闭的时候却是四次握手?
- 为什么TIME_WAIT状态需要经过2MSL(最大报文段生存时间)才能返回到CLOSE状态?
- 如果已经建立了连接,但是客户端突然出现故障了怎么办?
这些问题的答案见 :