理解 TCP(三):链接的创建和释放

更好阅读体验:《理解 TCP 和 UDP》— By Gitbook git

TCP 的整个交流过程能够总结为:先创建链接,而后传输数据,最后释放连接。 服务器

三次握手和四次挥手.png

三次握手,创建链接

TCP 链接创建要解决的首要问题就是:要使每一方可以确知对方的存在。 网络

三次握手就像,在一个黑暗的森林,你知道前方十点钟方向好像有人。
你喊了一句:Hello?I'am JerryC,Who are you?
对面回了一句:Hi! I'am David, and nice to meet you!
而后你回了一句:Nice to meet you too!
......(自此,大家才算真正认识了双方,开始了后面省略3000字的谈话) tcp

因此说,两我的须要交朋友(两个端点须要创建链接),至少须要三次的通话(握手) 计算机网络

其实,网络上的传输是没有链接的,TCP 也是同样的。
而 TCP 所谓的「链接」,其实只不过是在通讯的双方维护一个「链接状态」,让它看上去好像有链接同样。 设计

链接创建过程

TCP 链接的创建采用客户服务器方式,主动发起链接创建的一方叫客户端(Client),被动等待链接创建的一方叫服务器(Server)cdn

最初的时候,两端都处于 CLOSED 的状态,而后服务器打开了 TCP 服务,进入 LISTEN 状态,监听特定端口,等待客户端的 TCP 请求。 blog

第一次握手
客户端主动打开链接,发送 TCP 报文,进行第一次握手,而后进入 SYN_SEND 状态,等待服务器发回确认报文。
这时首部的同步位 SYN = 1,同时初始化一个序号 Sequence Number = J。
TCP 规定,SYN 报文段不能携带数据,但会消耗一个序号。 开发

第二次握手
服务器收到了 SYN 报文,若是赞成创建链接,则向客户端发送一个确认报文,而后服务器进入 SYN_RCVD 状态。
这时首部的 SYN = 1,ACK = 1,而确认号 Acknowledgemt Number = J + 1,同时也为本身初始化一个序号 Sequence Number = K。
这个报文一样不携带数据。 get

第三次握手
客户端收到了服务器发过来的确认报文,还要向服务器给出确认,而后进入 ESTABLISHED 状态。
这时首部的 SYN 再也不置为 1,而 ACK = 1,确认号 Acknowledgemt Number = K + 1,序号 Sequence Number = J + 1。
第三次握手,通常会携带真正须要传输的数据,当服务器收到该数据报文的时候,就会一样进入 ESTABLISHED 状态。
此时,TCP 链接已经创建。

对于创建链接的三次握手,主要目的是初始化序号 Sequence Number,而且通讯的双方都须要告知对方本身的初始化序号,因此这个过程也叫 SYN。
这个序号要做为之后的数据通讯的序号,以保证应用层接收到的数据不会由于网络上的传输问题而乱序,由于TCP 会用这个序号来拼接数据。

利用链接设计缺陷实施 TCP Flood 攻击

知道了 TCP 创建一个链接,须要进行三次握手。
但若是你开始思考「三次握手的必要性」的时候,就会知道,其实网络是很复杂的,一个信息在途中丢失的可能性是有的。
若是数据丢失了,那么,就须要从新发送,这时候就要知道数据是否真的送达了。
这就是三次握手的必要性。
可是再向深一层思考,你给我发信息,我收到了,我回复,由于我是君子。
若是是小人,你给我发信息,我就算收到了,我也不回复,你就一直等我着个人回复。
那么不少小人都这样作,你就要一直记住你在等待着小人1号、小人2号、小人3号......直到你的脑容量爆棚,烧坏脑壳。
黑客就是利用这样的设计缺陷,实施 TCP Flood 攻击,属于 DDOS 攻击的一种。
想了解更多 SYN Flood 攻击请看:SYN flood - wiki

四次挥手,释放链接

TCP 有一个特别的概念叫作半关闭,这个概念是说,TCP 的链接是全双工(能够同时发送和接收)的链接,所以在关闭链接的时候,必须关闭传送和接收两个方向上的链接。
客户端给服务器发送一个携带 FIN 的 TCP 结束报文段,而后服务器返回给客户端一个 确认报文段,同时发送一个 结束报文段,当客户端回复一个 确认报文段 以后,链接就结束了。

释放链接过程

在结束以前,通讯双方都是处于 ESTABLISHED 状态,而后其中一方主动断开链接。
下面假如客户端先主动断开链接。

第一次挥手:
客户端向服务器发送结束报文段,而后进入 FIN_WAIT_1 状态。
此报文段 FIN = 1, Sequence Number = M。

第二次挥手:
服务端收到客户端的结束报文段,而后发送确认报文段,进入 CLOSE_WAIT 状态。
此报文段 ACK = 1, Sequence Number = M + 1。

客户端收到该报文,会进入 FIN_WAIT_2 状态。

第三次挥手:
同时服务端向客户端发送结束报文段,而后进入 LAST_ACK 状态。
此报文段 FIN = 1,Sequence Number = N。

第四次挥手:
客户端收到服务端的结束报文段,而后发送确认报文段,进入 TIME_WAIT 状态,通过 2MSL 以后,自动进入 CLOSED 状态。
此报文段 ACK = 1, Sequence Number = N + 1。

服务端收到该报文以后,进入 CLOSED 状态。

关于 TIME_WAIT 过渡到 CLOSED 状态说明
TIME_WAIT 进入 CLOSED 须要通过 2MSL,其中 MSL 就叫作 最长报文段寿命(Maxinum Segment Lifetime),根据 RFC 793 建议该值这是为 2 分钟,也就是说须要通过 4 分钟,才进入 CLOSED 状态。

参考

《后台开发 核心技术与应用实践》
《计算机网络》

相关文章
相关标签/搜索