为何TCP创建链接协议是三次握手,而关闭链接倒是四次握手呢?

看到了一道面试题:“为何TCP创建链接协议是三次握手,而关闭链接倒是四次握手呢?为何不能用两次握手进行链接?”,想一想最近也到金三银四了,因此就查阅了相关资料,整理出来了这篇文章,但愿对大家有所帮助。面试

TCP 链接

咱们先来补一下基础什么是 TCP 协议?传输控制协议( Transmission Control Protocol, TCP )是种面向链接、确保数据在端到端间可靠传输的协议。面向链接是插在发送数据前,须要先创建一条虚拟的链路,而后让数据在这条链路上“流动”完成传输。服务器

TCP 是可靠的,会尽本身最大的努力去完成数据传输,TCP 协议比较复杂,能够看下面这张 TCP 协议的报文头图片:微信

TCP 协议报文头格式

内容很是的丰富,跟咱们今天要讨论的链接协议相关的就是中间那六个状态位: URG、ACK、PSH、RST、SYN、FIN ,都置为 1 表示有效,在这六个当中,咱们主要关注重点关注 ACK、SYN、FIN 这三个。下面解释一下这三个状态位:网络

ACK:用于对收到的数据进行确认,所确认的数据由确认序列号表示。tcp

SYN:用做创建链接时的同步信号学习

FIN:表示后面没有数据须要发送,一般意昧着所创建的链接须要关闭了。3d

好了,到这里,TCP 的基础知识咱们就知道了,下面咱们就来看看为何 是三次握手,而不是四次或者两次,为了让你更好的理解,我把知乎上一个高赞特别形象的比喻放在这里,但愿对你有所帮助。cdn

两次和四次都会出现问题,三次就刚恰好,但愿这张图可以让你更好的理解为何是三次握手。blog

咱们已经知道了 TCP 协议是三次握手,为何是三次握手呢?咱们先来看看下面这张 TCP 协议创建链接的时序图。图片

TCP 协议三次握手时序图

整体来讲就是呼叫、应答、回应,咱们来详细的介绍每一步:

  • 第一步: A 机器向 B机器发出一个数据包并将 SYN 设置为 1 ,表示但愿创建链接。这个包中的序列号假设是 X。
  • 第二步: B 机器收到 A机器发过来的数据包后,经过 SYN 得知这是一个创建链接的请求,因而发送一个响应包并将 SYN 、ACK 标记都置为 1。假设这个包中的序列号是 y ,而确认序列号必须是 x+l ,表示收到了 发过来的 SYN,TCP 中, SYN 被看成数据部分的一个字节。
  • 第三步: A 收到 的响应包后需进行确认,确认包中将 ACK ,并将确认序列号设置为 y+ ,表示收到了来自B 的 SYN

通过这三步以后,两台服务器就创建链接了,能够进行通讯数据传输了。为何要三次握手呢?主要是为了信息对等和防止出现请求超时致使脏链接。

第一是为了保证两台机器信息对等,确保两台机器都没有什么问题:

信息对称

只有三次握手以后才可以保证两台服务器都彻底没有问题,各自具有发报和收报能力。

第二是防止出现请求超时致使脏链接,看下面这张图:

防止出现请求超时致使脏链接

为何会出现脏链接?由于TTL 网络报文的生存时间每每都会超 TCP 请求超时时间,若是两次握手就能够建立链接 ,传输数据并释放链接后,第一个超时的链接请求才到达 B 机器的话,B 机器会觉得是 A 建立新链接的请求,而后确认赞成建立链接。由于 A 机器的状态不是 SYl_SENT ,因此直接丢弃了 B 的确认数据 ,以至最后只是 B 机器单方面建立链接完毕。

三次握手就能够解决这个问题,由于须要 A 服务器确认了才真正的创建了链接。

TCP 四次挥手

上面介绍了 TCP 协议链接,有链接就有断开,相对于三次链接,断开却须要四次挥手,怎么理解呢?先看下面这个场景:

A:B 啊,我不想玩了。

B:哦,你不想玩了啊,我知道了。

这个时候,还只是 A 不想玩了,也即 A 不会再发送数据,可是 B 能不能在 ACK 的时候,直接关闭呢?固然不能够了,颇有可能 A 是发完了最后的数据就准备不玩了,可是 B 还没作完本身的事情,仍是能够发送数据的,因此称为半关闭的状态

这个时候 A 能够选择再也不接收数据了,也能够选择最后再接收一段数据,等待 B 也主动关闭。

B:A 啊,好吧,我也不玩了,拜拜。

A:好的,拜拜。

这就是一个完整的关闭链接,在这个关闭的过程当中,一共说了四句话,咱们也称之为四次挥手。跟创建链接同样,断开时也是用状态来表示,下面是断开的时序图:

状态时序图

咱们结合上面的时序图和场景再来分析一下 TCP 断开过程。

当 A 说“不玩了”,A 就进入 FIN_WAIT_1 的状态,B 收到“A 不玩”的消息后,发送知道了,B 就进入 CLOSE_WAIT 的状态。

A 收到“B 说知道了”,就进入 FIN_WAIT_2 的状态,若是这个时候 B 直接跑路,则 A 将永远在这个状态。虽然 TCP 协议里面并无对这个状态的处理,可是 Linux 有,能够调整 tcp_fin_timeout 这个参数,设置一个超时时间,最后 A 也会关闭的。

若是 B 没有跑路,发送了“B 也不玩了”的请求到达 A 时,A 发送“知道 B 也不玩了”的 ACK 后,从 FIN_WAIT_2 状态结束,按说 A 能够跑路了,可是最后的这个 ACK 万一 B 收不到呢?则 B 会从新发一个“B 不玩了”,这个时候 A 已经跑路了的话,B 就再也收不到 ACK 了,于是 TCP 协议要求 A 最后等待一段时间 TIME_WAIT,这个时间要足够长,长到若是 B 没收到 ACK 的话,“B 说不玩了”会重发的,A 会从新发一个 ACK 而且足够时间到达 B。

要求 A 等待 TIME_WAIT还有一个缘由就是防止产生混乱,A 直接关闭了,可是这个时候 B是不知道的,可能在 A 关闭以前 B还发送了不少数据包,若是这时候 A 的端口被一个新的应用占用了的话,那么新的应用就会接收到上个链接中 B发送过来的数据包,这样就混乱了,虽然这个数据包是无效的,可是等待 TIME_WAIT 能够是一个双保险,于是也须要等足够长的时间,等到原来 B 发送的全部的包都死翘翘,再空出端口来。

以上就是 TCP 协议三次握手,四次挥手的缘由,但愿这篇文章对您的学习或者工做有所帮助,若是您以为文章不错,还请您帮忙点个赞和转发,谢谢。

最后

目前互联网上不少大佬都有 TCP 协议相关文章,若有雷同,请多多包涵了。原创不易,码字不易,还但愿你们多多支持。若文中有所错误之处,还望提出,谢谢。

欢迎扫码关注微信公众号:「平头哥的技术博文」,和平头哥一块儿学习,一块儿进步。

平头哥的技术博文
相关文章
相关标签/搜索