您的位置:首页 > 理论基础 > 计算机网络

深入理解TCP三次握手

2018-04-02 11:08 169 查看

三次握手

在《计算机网络》一书中其中有提到,三次握手的目的是“为了防止已经失效的连接请求报文段突然又传到服务端,因而产生错误”,这种情况是:一端(client)A发出去的第一个连接请求报文并没有丢失,而是因为某些未知的原因在某个网络节点上发生滞留,导致延迟到连接释放以后的某个时间才到达另一端(server)B。本来这是一个早已失效的报文段,但是B收到此失效的报文之后,会误认为是A再次发出的一个新的连接请求,于是B端就向A又发出确认报文,表示同意建立连接。如果不采用“三次握手”,那么只要B端发出确认报文就会认为新的连接已经建立了,但是A端并没有发出建立连接的请求,因此不会去向B端发送数据,B端没有收到数据就会一直等待,这样B端就会白白浪费掉很多资源。如果采用“三次握手”的话就不会出现这种情况,B端收到一个过时失效的报文段之后,向A端发出确认,此时A并没有要求建立连接,所以就不会向B端发送确认,这个时候B端也能够知道连接没有建立。

问题的本质是,信道是不可靠的,但是我们要建立可靠的连接发送可靠的数据,也就是数据传输是需要可靠的。在这个时候三次握手是一个理论上的最小值,并不是说是tcp协议要求的,而是为了满足在不可靠的信道上传输可靠的数据所要求的。

我们再来考虑,如果不是三次握手会出现什么情况呢:

假设有A和B两端要进行通信,
1, 第一次:首先A发送一个(SYN)到B,意思是A要和B建立连接进行通信;
如果是只有一次握手的话,这样肯定是不行的,A压根都不知道B是不是收到了这个请求。
2, 第二次:B收到A要建立连接的请求之后,发送一个确认(SYN+ACK)给A,意思是收到A的消息了,B这里也是通的,表示可以建立连接;
如果只有两次通信的话,这时候B不确定A是否收到了确认消息,有可能这个确认消息由于某些原因丢了。
3, 第三次:A如果收到了B的确认消息之后,再发出一个确认(ACK)消息,意思是告诉B,这边是通的,然后A和B就可以建立连接相互通信了;
这个时候经过了三次握手,A和B双方确认了两边都是通的,可以相互通信了,已经可以建立一个可靠的连接,并且可以相互发送数据。
4, 第四次:这个时候已经不需要B再发送一个确认消息了,两边已经通过前三次建立了一个可靠的连接,如果再发送第四次确认消息的话,就浪费资源了。
如果第二个报文段B发出的(SYN+ACK)分别发送的话,也是可以理解为四次,但是被优化了,一起发送了。
超时重传机制,
(1) 如果第一个包,A发送给B请求建立连接的报文(SYN)如果丢掉了,A会周期性的超时重传,直到B发出确认(SYN+ACK);
(2) 如果第二个包,B发送给A的确认报文(SYN+ACK)如果丢掉了,B会周期性的超时重传,直到A发出确认(ACK);
(3) 如果第三个包,A发送给B的确认报文(ACK)如果丢掉了,
A在发送完确认报文之后,单方面会进入ESTABLISHED的状态,B还是SYN_RCVD状态
如果此时双方都没有数据需要发送,B会周期性的超时发送(SYN+ACK),直到收到A的确认报文(ACK),此时B也进入ESTABLISHED状态,双方可以发送数据;
如果A有数据发送,A发送的是(ACK+DATA),B会在收到这个数据包的时候自动切换到ESTABLISHED状态,并接受数据(DATA);
如果这个时候B要发送数据,B是发送不了数据的,会周期性的超时重传(SYN+ACK)直到收到A的确认(ACK)B才能发送数据。
三次握手牵扯到的状态转换
** LISTEN ** 表示socket已经处于listen状态了,可以建立连接;
** SYN_SENT ** 表示socket在发出connect连接的时候,会首先发送SYN报文,然后等待另一端发送的确认报文(ACK),表示这端已经发送完SYN报文了;
** SYN_RCVD ** 表示一端已经接收到SYN报文了;
** ESTABLISHED ** 表示已经建立连接了,可以发送数据了。

四次挥手

说完TCP建立连接的时候为什么是三次,相对的就会想到为什么断开连接的时候是需要四次呢,而不是三次,五次等等呢;
本质的原因是tcp是全双公的,要实现可靠的连接关闭,A发出结束报文FIN,收到B确认后A知道自己没有数据需要发送了,B知道A不再发送数据了,自己也不会接收数据了,但是此时A还是可以接收数据,B也可以发送数据;当B发出FIN报文的时候此时两边才会真正的断开连接,读写分开。
四次挥手牵扯到的状态装换
** FIN_WAIT_1 ** 表示在等待另一方的FIN报文,和FIN_WAIT_2的区别是,FIN_WAIT_1表示socket现在要主动关闭连接,在发送完FIN报文后socket进入FIN_WAIT_1状态,当收到另一方发送FIN的ACK之后立即进入FIN_WAIT_2状态;
** FIN_WAIT_2 ** 同上,此时需要做的事情是可能还会接收数据,然后等待另一方的FIN;
** TIME_WAIT ** 存在主动关闭的一方,表示收到了对方的FIN报文,并发送出了ACK报文,就等2MSL(Max Segment Lifetime))后即可回到CLOSED可用状态了,需要等一段时间时原因是网络是不可靠的,不能保证这个ACK发送成功了,如果失败了,对端会超时重传FIN;
** CLOSING ** 表示在发送FIN之后,没有收到对方的ACK,而是收到了对方的FIN,这中情况很少见,只有在两端几乎同时关闭同一个socket的时候才会出现CLOSING状态;
** CLOSE_WAIT ** 表示收到对方的FIN之后,回给对方ACK,此时处于CLOSE_WAIT状态,等待关闭,要看自己是否还有数据要发送;
** LAST_ACK ** 表示收到对方的FIN之后,回给对方ACK,然后自己也要关闭发送FIN,等待另一方的ACK时候的状态;
** CLOSED ** 这个状态表示连接已经断开。



原文地址:https://www.jianshu.com/p/e7f45779008a
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐