三次握手,四次挥手超详细解释

119 阅读10分钟

三次握手和四次挥手(运输层协议)

1)三次握手过程

image.png

image.png 准备:首先TCP服务器进程创建传输控制块,然后进入监听状态,等待TCP客户进程的连接请求。TCP服务器进程是被动等待来自TCP客户进程的连接请求,而不是被动发起,所以被称为被动打开连接。 第一次握手:TCP客户进程也是首先创建传输控制块,然后在打算建立TCP连接时,向TCP服务器进程发送TCP连接请求报文段,并进入同步已发送状态。TCP连接请求报文段首部中的同步位SYN被设置为1,表明这是一个TCP连接请求报文段,序号字段seq被设置了一个初始值x,作为TCP客户进程所选择的初始序号。(请注意:TCP规定SYN被设置为1的报文段不能携带数据,但要消耗掉一个序号)由于TCP连接建立是由TCP客户主动发起的,所以叫主动打开连接。 第二次握手:TCP服务器进程收到TCP连接请求报文段后,如果同意建立连接,则向TCP客户进程发送TCP连接请求确认报文段,并进入同步已接受状态。该报文段首部中的同步位SYN和确认ACK都设置为1,表明这是一个TCP连接请求确认报文段。序号字段seq被设置了一个初始值y作为TCP服务器进程所选择的初始序号。确认号字段ack的值被设置成了x+1,这是对TCP客户进程所选择的初始序号的确认。(请注意:这个报文段也不能携带数据,因为它是SYN被设置为1的报文段,但同样要消耗掉一个序号) 第三次握手:TCP客户进程收到TCP连接请求确认报文段后,还要向TCP服务器进程发送一个普通的TCP确认报文段,并进入连接已建立状态,该报文段首部中的确认位ACK被设置为1,表明这是一个普通的TCP确认报文段。序号字段seq被设置为x+1,这是因为TCP客户进程发送的第一个TCP报文段的序号为x,并且不携带数据,因此第二个报文段的序号为x+1。(请注意:TCP规定普通的TCP确认报文段可以携带数据,但如果不携带数据,则不消耗序号。)在这种情况下,所发送的下一个数据报文段的序号仍是x+1。确认号字段ack被设置为y+1,这是对TCP服务器进程所选择的初始序号的确认。TCP服务器进程收到该确认报文段后也进入连接已建立状态。现在,TCP双方都进入了连接已建立状态,此时就可以基于已建立好的TCP连接进行可靠的数据传输了

2)为什么不能两次握手?而必须要三次握手?(最后一次握手可否不要?)

不能。 考虑这样一种情况,TCP客户进程发出一个TCP连接请求报文段。但该报文段在某些网络结点长时间滞留了。这必然会造成该报文段的超时重传,假设重传的报文段被TCP服务器进程正常接受。TCP服务器进程给TCP客户进程发送一个TCP连接请求确认报文段,并进入连接已建立状态。(请注意:由于我们改为“两报文握手”)因此TCP服务器进程发送完TCP连接请求确认报文段后进入的是连接已建立状态,而不像“三报文握手”那样进入同步已接受状态,并等待TCP客户进程发来针对TCP连接请求确认报文段的普通确认报文段。TCP客户进程收到TCP连接请求确认报文段后,进入TCP连接已建立状态。但不会给TCP服务器进程发送针对该报文段的普通确认报文段。现在,TCP双方都处于连接已建立状态,他们可以相互传输数据。 之后可以通过“四报文挥手”来释放连接,TCP双方都进入了关闭状态。 一段时间后,之前滞留在网络中的那个失效的TCP连接请求报文段到达了TCP服务器进程。TCP服务器进程会误认为这是TCP客户进程又发起了一个新的TCP连接请求,于是给TCP客户进程发送TCP连接请求确认报文段,并进入连接已建立状态,该报文段到达TCP客户进程,由于TCP客户进程并没有发起新的TCP连接请求,并且处于关闭状态,因此不会理会该报文段。但TCP服务器进程已进入连接已建立状态,它认为新的TCP连接已建立好了,并一直等待TCP客户进程发来数据,这将白白浪费TCP服务器进程所在主机的很多资源。 综上所述,采用个“三报文握手”,而不是“两报文握手”来建立TCP连接,是为了防止已失效的请求报文段突然又传送到了TCP服务器,因而导致错误。

3)四次挥手

image.png 准备:TCP数据传输完毕后,TCP双方都可以释放连接。现在TCP客户进程和TCP服务器进程都处于连接已建立状态。 第一次挥手:假设只用TCP客户进程的应用进程通知其主动关闭TCP连接,TCP客户进程会发送TCP连接释放报文段并进入终止等待1状态。该报文段首部中的终止位FIN和确认位ACK的值都被设置为1,表明这是一个TCP连接释放报文段,同时也对之前收到的报文段进行确认。序号seq字段的值设置为u,它等于TCP客户进程之前已传送过的、数据的最后一个字节的序号加1。(请注意:TCP规定中值为FIN等于1的报文段即使不携带数据,也要消耗掉一个序号。)确认好ack字段的值设置为v,它等于TCP客户进程之前已收到的、数据的最后一个字节的序号加1。 第二次挥手:TCP服务器进程收到TCP连接释放报文段后,会发送一个普通的TCP确认报文段并进入关闭等待状态。该报文段手不中的确认位ACK的值被设置为1,表明这是一个普通的TCP确认报文段。序号seq字段的值设置为v,它等于TCP服务器进程之前已传送过的数据的最后一个字节的序号加1。这也与之前收到的TCP连接释放报文段中的确认号匹配。确认好ack字段的值设置为u+1,这是对TCP连接释放报文段的确认。TCP服务器进程这时应通知高层应用进程:TCP客户进程要断开与自己的TCP连接。此时,从TCP客进程到TCP服务器进程这个方向的连接就释放了。这是的TCP连接属于瓣关闭状态,也就是TCP客户进程已经没有数据要发送了,但TCP服务器进程如果还有数据要发送,TCP客户进程仍要接受。也就是说,从TCP服务器进程到TCP客户进程这个方向的连接并未关闭,这个状态可能会持续一段时间。 第三次挥手:TCP客户进程收到TCP确认报文段后就进入终止等待2状态。等待TCP服务器进程发出的TCP连接释放报文段。若使用TCP服务器进程的应用进程已经没有数据要发送了,应用进程就通知其TCP服务器进程释放连接。由于TCP连接释放是由TCP客户进程主动发起的,因此TCP服务器进程对TCP连接的释放成为被动关闭连接。 第四次挥手:TCP服务器进程发送TCP连接释放报文段并进入最后确认状态。该报文段首部中的终止位FIN和确认位ACK的值都被设置为1,表明这是一个TCP连接释放报文段,同时也对之前收到的报文段进行确认。现在假定序号seq字段的值为w。这是因为在半关闭状态下,TCP服务器进程可能又发送了一些数据。确认号ack字段的值为u+1,这是对之前收到的TCP连接释放报文段的重复确认。 TCP客户进程收到TCP连接释放报文段后,必须针对该报文段发送普通的TCP确认报文段,之后进入时间等待状态。该报文段首部中的确认位ACK的值被设置为1,表明这是一个普通的TCP确认报文段。序号seq字段的值被设置为u+1,这是因为TCP客户进程之前发送的TCP连接释放报文段虽然不携带数据,但要消耗掉一个序号。确认号ack字段的值设置为w+1,这是对所收到的TCP连接释放报文段的确认。 TCP服务器进程收到该报文段后就进入关闭状态。而TCP客户进程还要经过2MSL后才能进入关闭状态。(MSL的意思是最长报文段寿命,一般为2分钟)也就是说TCP客户进程进入时间等待状态后,还要经过4分钟才能进入关闭状态。(现在一般可根据具体情况设置更小的MSL值)

4)四次挥手中,最终客户端为什么要等2MSL的时间才关闭?

image.png 特殊情况:在TCP服务器进程发送TCP连接释放报文段后进入最后确认状态。TCP客户进程收到该报文段后,发送普通的TCP确认报文段,并进入关闭状态而不是时间等待状态。然而该TCP确认报文段丢失了。这会造成TCP服务器进程对之前所发送的TCP连接释放报文段的超时重传,并仍处于最后确认状态。重传的TCP连接释放报文段到达TCP客户进程。由于TCP客户进程属于关闭状态,因此不理睬该报文段,这会造成TCP服务器进程反复重传TCP连接释放报文段,并一直处于最后确认状态而无法进入关闭状态。因此,时间等待状态以及处于该状态2MSL时长,可以确保TCP服务器进程可以收到最后一个TCP确认报文段而进入关闭状态。另外,TCP客户进程在发送完最后一个TCP确认报文段后,再经过2MSL时长,就可以使本次连接持续时间内所产生的的所有报文段都从网络消失,这样就可以使下一个新的TCP连接中,不会出现就连接中的报文段。 5)为什么不可以三次挥手,既把服务端发送的两次合并? 因为客户端发送Fin=1的断开连接请求报文,服务器端可能还有未传输完成的剩余数据,所以服务器端在收到客户端的断开请求时,首先对客户端的断开请求报文做回应,发送ACK=1的确认收到,表示:客户端发的FIN=1报文服务端收到了 ,但是并不意味这数据传输完毕,等待服务器端数据全部传输完毕后,服务器端返回Fin=1的释放连接报文。