一、TCP协议三次握手,四次挥手详解
前言
为什么TCP协议需要三次握手和四次挥手?
TCP协议介绍
传输控制协议(TCP,Transmission Control Protocol)是一种面向连接的、可靠的、基于字节流的传输层通信协议.
三次握手
标识位:
SYN:Synchronize Sequence Numbers,同步序列编号
ACK:Acknowledge Character,确认字符
seq:随机序列号
ack:确认序列号
三次握手流程
第一次:客户端向服务端发送连接请求报文段,标识为syn(建立连接),产生一个序列号seq=x,表明传送数据时的第一个数据字节序号为 x
第二次:服务端的TCP 收到连接请求报文段后,如果同意,则发挥连接同意报文
服务端在连接同意报文中使用俩个标识SYN和ACK,其随机序列号为seq=y,确认序列号为ack=x+1
第三次:客户端收到服务端的报文,发送确认报文ACK,随机序列号为seq=x+1,ack=y+1
服务端和客户端收到确认报文,通知上层应用进程:TCP连接已建立
四次挥手
首先解释为什么需要四次挥手?
TCP是基于全双工通信的,所以双方都可以主动释放连接。
四次挥手的意义就在于,当 A 发送完最后一条数据之后,但可能B还有未发送给A 的数据。
所以A在发送完收据后可以请求释放连接,此时B给与A响应,告诉A我知道你想断开连接,此时A还可以继续接收B发送的信息。
在B处理完工作后,也请求释放连接。A同意后,就断开连接。
这样可以保证数据正常可靠的交互。
四次挥手流程
FIN : 标志位,请求关闭连接
第一次:数据传输结束后,通信双方都可以释放连接
假设A已经向B传输完数据,A就可以发生释放连接报文段,并停止发送数据,主动关闭TCP连接
A 连接释放报文首部 FIN,其序列号 seq = u,等待 B 的确认。
第二次:B收到后,发送确认报文,意思是我收到了确认号 ack = u+1,而这个报文段自己的序号为seq = v
从A 到 B 这个方向的连接就释放了,TCP 连接处于半关闭状态。B 若发送数据,A仍需要接收
第三次:当B发送完数据后,就可以释放连接。
B 发出的连接释放报文 的 FIN,序号为w,ack仍为u+1
第四次: A 收到连接释放报文后,必须发出确认。确认好 ack = w +1,序号seq = u+1。
至此,双方断开连接
二、什么是TCP协议?
- TCP是一种面向连接的、可靠的、基于字节流的传输层通信协议,在发送数据前,通信双方 必须在彼此间建立一条连接,所谓的连接其实就是客服端和服务端保存的一份关于对方的信息,如ip地址、端口号等。
- TCP可以看成是一种字节流,它会处理IP层或以下层的丢包、重复以及错误问题。
- 在建立连接的过程中,双方需要交换一些连接参数,这些参数可以放在TCP头部。一个TCP连接由一个4元组构成,分别是两个IP地址和两个端口号。
- 一个TCP连接通常分为三个阶段:连接、数据传输、退出(关闭)。通过三次握手来建立一个链接,通过四次挥手来关闭一个链接。
- 当一个链接被建立或者被终止时,交换的报文段只包含TCP头部而没有数据。
三、三次握手
三次握手的本质是确认通信双方收发数据的能力。
首先,我让信使运输一份信件给对方,对方收到了,那么他就知道了我的发件能力和他的收件能力是可以的。于是他给我回信,我若收到了,我便知我的发件能力和他的收件能力是可以的,并且他的发件能力和我的收件能力是可以。然而此时他还不知道他的发件能力和我的收件能力到底可不可以,于是我最后回馈一次,他若收到了,他便清楚了他的发件能力和我的收件能力是可以的。这,就是三次握手。
第一次握手:
客户端要向服务端发起连接请求,首先客户端随机生成一个起始序列号ISN(比如是100),那客户端向服务端发送的报文段包含SYN标志位(也就是SYN=1),序列号seq=100。
第二次握手:
服务端收到客户端发过来的报文后,发现SYN=1,知道这是一个连接请求,于是将客户端的起始序列号100存起来,并且随机生成一个服务端的起始序列号(比如是300)。然后给客户端回复一段报文,回复报文包含SYN和ACK标志(也就是SYN=1,ACK=1)、序列号seq=300、确认号ack=101(客户端发过来的序列号+1)。
第三次握手:
客户端收到服务端的回复后发现ACK=1并且ack=101,于是知道服务端已经收到了序列号为100的那段报文;同时发现SYN=1,知道了服务端同意了这次连接,于是就将服务端的序列号300给存下来。然后客户端再回复一段报文给服务端,报文包含ACK标志位(ACK=1)、ack=301(服务端序列号+1)、seq=101(第一次握手时发送报文是占据一个序列号的,所以这次seq就从101开始,需要注意的是不携带数据的ACK报文是不占据序列号的,所以后面第一次正式发送数据时seq还是101)。当服务端收到报文后发现ACK=1并且ack=301,就知道客户端收到序列号为300的报文了,就这样客户端和服务端通过TCP建立了连接。
四、四次挥手
比如客户端初始化的序列号ISA=100,服务端初始化的序列号ISA=300。TCP连接成功后客户端总共发送了1000个字节的数据,服务端在客户端发FIN报文前总共回复了2000个字节的数据。
第一次挥手:
当客户端的数据都传输完成后,客户端向服务端发出连接释放报文(当然数据没发完时也可以发送连接释放报文并停止发送数据),释放连接报文包含FIN标志位(FIN=1)、序列号seq=1101(100+1+1000,其中的1是建立连接时占的一个序列号)。需要注意的是客户端发出FIN报文段后只是不能发数据了,但是还可以正常收数据;另外FIN报文段即使不携带数据也要占据一个序列号。
第二次挥手:
服务端收到客户端发的FIN报文后给客户端回复确认报文,确认报文包含ACK标志位(ACK=1)、确认号ack=1102(客户端FIN报文序列号1101+1)、序列号seq=2300(300+2000)。此时服务端处于关闭等待状态,而不是立马给客户端发FIN报文,这个状态还要持续一段时间,因为服务端可能还有数据没发完。
第三次挥手:
服务端将最后数据(比如50个字节)发送完毕后就向客户端发出连接释放报文,报文包含FIN和ACK标志位(FIN=1,ACK=1)、确认号和第二次挥手一样ack=1102、序列号seq=2350(2300+50)。
第四次挥手:
客户端收到服务端发的FIN报文后,向服务端发出确认报文,确认报文包含ACK标志位(ACK=1)、确认号ack=2351、序列号seq=1102。注意客户端发出确认报文后不是立马释放TCP连接,而是要经过2MSL(最长报文段寿命的2倍时长)后才释放TCP连接。而服务端一旦收到客户端发出的确认报文就会立马释放TCP连接,所以服务端结束TCP连接的时间要比客户端早一些。
五、常见面试题
5.1 为什么TCP连接的时候是3次?2次不可以吗?
因为需要考虑连接时丢包的问题,如果只握手2次,第二次握手时如果服务端发给客户端的确认报文段丢失,此时服务端已经准备好了收发数(可以理解服务端已经连接成功)据,而客户端一直没收到服务端的确认报文,所以客户端就不知道服务端是否已经准备好了(可以理解为客户端未连接成功),这种情况下客户端不会给服务端发数据,也会忽略服务端发过来的数据。
如果是三次握手,即便发生丢包也不会有问题,比如如果第三次握手客户端发的确认ack报文丢失,服务端在一段时间内没有收到确认ack报文的话就会重新进行第二次握手,也就是服务端会重发SYN报文段,客户端收到重发的报文段后会再次给服务端发送确认ack报文。
5.2 为什么TCP连接的时候是3次,关闭的时候却是4次?
因为只有在客户端和服务端都没有数据要发送的时候才能断开TCP。而客户端发出FIN报文时只能保证客户端没有数据发了,服务端还有没有数据发客户端是不知道的。而服务端收到客户端的FIN报文后只能先回复客户端一个确认报文来告诉客户端我服务端已经收到你的FIN报文了,但我服务端还有一些数据没发完,等这些数据发完了服务端才能给客户端发FIN报文(所以不能一次性将确认报文和FIN报文发给客户端,就是这里多出来了一次)。
5.3 为什么客户端发出第四次挥手的确认报文后要等2MSL的时间才能释放TCP连接?
这里同样是要考虑丢包的问题,如果第四次挥手的报文丢失,服务端没收到确认ack报文就会重发第三次挥手的报文,这样报文一去一回最长时间就是2MSL,所以需要等这么长时间来确认服务端确实已经收到了。