4、增加最大半连接数。5、过滤网关防护。6、SYN cookie技术。
:有一点点重新“设计” TCP 的味道,或者可以理解成对 TCP 的增强。
【重要】什么是 TCP 四次挥手?
四次挥手,简单来说,就是:
发送方:我要和你断开连接!接收方:好的,断吧。接收方:我也要和你断开连接!发送方:好的,断吧。详细来说,步骤如下:
如下使用 Client 和 Server 的方式,仅仅是为了方便,也是可以从 Server 向 Client 发起。
第一次挥手:Client 发送一个 FIN=M ,用来关闭 Client 到 Server 的数据传送。此时,Client 进入FIN_WAIT_1 状态。
第二次挥手,Server 收到 FIN 后,发送一个 ACK 给 Client ,确认序号为 M+1(与 SYN 相同,一个
FIN占用一个序号)。此时,Server 进入 CLOSE_WAIT 状态。注意,TCP 链接处于半关闭状态,即客户端
已经没有要发送的数据了,但服务端若发送数据,则客户端仍要接收。第三次挥手,Server 发送一个 FIN=N ,用来关闭 Server 到 Client 的数据传送。此时 Server 进入LAST_ACK 状态。
第四次挥手,Client 收到 FIN 后,此时 Client 进入 TIME_WAIT 状态。接着,Client 发送一个 ACK 给Server ,确认序号为 N+1 。Server 接收到后,此时 Server 进入 CLOSED 状态,完成四次挥手。?? 为什么要四次挥手?
TCP 协议是一种面向连接的、可靠的、基于字节流的运输层通信协议。TCP 是全双工模式,这就意味着:
当主机 1 发出 FIN 报文段时,只是表示主机 1 已经没有数据要发送了,主机 1 告诉主机 2 ,它的数据已经全部发送完毕了;但是,这个时候主机 1 还是可以接受来自主机 2 的数据;当主机 2 返回 ACK 报文段时,表示它已经知道主机 1 没有数据发送了,但是主机 2 还是可以发送数据到主机 1 的。
:因为主机 2 此时可能还有数据想要发送给主机 1 ,所以挥手不能像握手只有三次,而是多了那么“一次”!
当主机 2 也发送了 FIN 报文段时,这个时候就表示主机 2 也没有数据要发送了,就会告诉主机 1 ,我也没有数据要发送了,之后彼此就会愉快的中断这次 TCP 连接。:我们把四次挥手,理解成一次和平的挥手~
如果要正确的理解四次的原理,就需要了解四次挥手过程中的状态变化。主动方=发送方;被动方=接收方。
状态前面的(主动方)(被动方),表示该状态属于谁。
(主动方)FIN_WAIT_1 :这个状态要好好解释一下,其实 FIN_WAIT_1 和 FIN_WAIT_2 状态的真正含义都是表示等待对方的FIN报文。而这两种状态的区别是:FIN_WAIT_1 状态实际上是当 Socket 在 ESTABLISHED 状态时,它想主动关闭连接,向对方发送了 FIN报文,此时该 Socket 即进入到 FIN_WAIT_1 状态。
而当对方回应 ACK 报文后,则进入到 FIN_WAIT_2 状态,当然在实际的正常情况下,无论对方何种情况下,都应该马上回应ACK 报文。所以, FIN_WAIT_1 状态一般是比较难见到的,而 FIN_WAIT_2 状态还有时常常可以用 netstat 看到。(主动方)FIN_WAIT_2 :上面已经详细解释了这种状态,实际上 FIN_WAIT_2 状态下的 Socket,表示半连接,也即有一方要求 close 连接,但另外还告诉对方,我暂时还有点数据需要传送给你(ACK 信息),稍后再关闭连接。
(被动方)CLOSE_WAIT :这种状态的含义其实是表示在等待关闭。怎么理解呢?当对方 close 一个 Socket后发送 FIN 报文给自己,你系统毫无疑问地会回应一个 ACK 报文给对方,此时则进入到 CLOSE_WAIT 状态。接下来呢,实际上你真正需要考虑的事情是察看你是否还有数据发送给对方,如果没有的话,那么你也就可以 close 这个 Socket ,发送 FIN 报文给对方,也即关闭连接。所以你在 CLOSE_WAIT 状态下,需要完成的事情是等待你去关闭连接。
(被动方)LAST_ACK :这个状态还是比较容易好理解的,它是被动关闭一方在发送 FIN 报文后,最后等待对方的 ACK 报文。当收到 ACK 报文后,也即可以进入到 CLOSED 可用状态了。
(主动方)TIME_WAIT :表示收到了对方的 FIN 报文,并发送出了 ACK 报文,就等 2MSL 后即可回到CLOSED 可用状态了。如果 FIN_WAIT_1 状态下,收到了对方同时带 FIN 标志和 ACK 标志的报文时,可以直接进入到 TIME_WAIT 状态,而无须经过 FIN_WAIT_2 状态。为何一定要等 2MSL ?
如果不等,释放的端口可能会重连刚断开的服务器端口,这样依然存活在网络里的老的 TCP 报文可能与新 TCP 连接报文冲突,造成数据冲突,为避免此种情况,需要耐心等待网络老的 TCP 连接的活跃报文全部死翘翘,2MSL 时间可以满足这个需求(尽管非常保守)!
更多,可以看看知乎 《为什么 TCP 4 次挥手时等待为 2MSL?》 的讨论。CLOSED :表示连接中断。
另外,关于 TIME_WAIT 和 CLOSE_WAIT 状态的区别,胖友可以在细看下 《TIME_WAIT 和 CLOSE_WAIT 状态区别》 。
【重要】TCP 数据如何传输?
建立连接后,两台主机就可以相互传输数据了。如下图所示:
上图给出了主机 A 分 2 次(分 2 个数据包)向主机 B 传递 200 字节的过程。
首先,主机 A 通过 1 个数据包发送 100 个字节的数据,数据包的Seq号设置为 1200 。主机 B 为了确认这一点,向主机 A 发送ACK包,并将Ack号设置为 1301 。
为了保证数据准确到达,目标机器在收到数据包(包括 SYN 包、FIN 包、普通数据包等)包后必须立即回传 ACK 包,这样发送方才能确认数据传输成功。
此时Ack号为 1301 而不是 1201,原因在于Ack号的增量为传输的数据字节数。假设每次Ack号不加传输的字节数,这样虽然可以确认数据包的传输,但无法明确 100 字节全部正确传递还是丢失了一部分,比如只传递了 80 字节。因此按如下的公式确认:
Ack号:Ack号 =Seq号 + 传递的字节数 + 1 。
与三次握手协议相同,最后加 1 是为了告诉对方要传递的 Seq 号。
OK,让我们重新来看下 TCP 的整个过程。如下图所示:TCP 过程?? TCP 数据传输丢失怎么办?
:这个问题,也可以改成提问,什么是 TCP 重传。
因为各种原因,TCP 数据包可能存在丢失的情况,TCP 会进行数据重传。如下图所示:
上图表示通过 Seq 1301 数据包向主机 B 传递 100 字节的数据,但中间发生了错误,主机 B 未收到。经过一段时间后,主机 A 仍未收到对于 Seq 1301 的 ACK 确认,因此尝试重传数据。为了完成数据包的重传,TCP 套接字每次发送数据包时都会启动定时器,如果在一定时间内没有收到目标机器传回的 ACK 包,那么定时器超时,数据包会重传。上图演示的是数据包丢失的情况,也会有 ACK 包丢失的情况,一样会重传。重传超时时间(RTO,Retransmission Time Out)
这个值太大了会导致不必要的等待,太小会导致不必要的重传,理论上最好是网络 RTT 时间,但又受制于网络距离与瞬态时延变化,所以实际上使用自适应的动态算法(例如 Jacobson 算法和 Karn 算法等)来确定超时时间。
往返时间(RTT,Round-Trip Time)表示从发送端发送数据开始,到发送端收到来自接收端的 ACK确认包(接收端收到数据后便立即确认),总共经历的时延。重传次数
TCP 数据包重传次数,根据系统设置的不同而有所区别。有些系统,一个数据包只会被重传 3 次,如果重传 3 次后还未收到该数据包的 ACK 确认,就不再尝试重传。但有些要求很高的业务系统,会不断地重传丢失的数据包,以尽最大可能保证业务数据的正常交互。最后需要说明的是,发送端只有在收到对方的 ACK 确认包后,才会清空输出缓冲区中的数据。
ps:TCP 数据传输的过程,和 MQ Broker 投递消息给 Consumer 是一样的,只有在 Consumer Ack 确认消息已经消费,该消息才不会再被投递给 Consumer 。
另外,也推荐阅读 《网络基本功(九):细说TCP重传》 。
【重要】什么是 TCP 滑动窗口?
在看 TCP 滑动窗口的概念之前,我们先来看看它出现的背景?
将 TCP 与 UDP 这样的简单传输协议区分开来的是,它传输数据的质量。TCP 对于发送数据进行跟踪,这种数据管理需要协议有以下两大关键功能:
可靠性:保证数据确实到达目的地。如果未到达,能够发现并重传。数据流控:管理数据的发送速率,以使接收设备不致于过载。
要完成这些任务,整个协议操作是围绕滑动窗口 + 确认机制来进行的。因此,理解了滑动窗口,也就是理解了 TCP 。
那么,到底什么是 TCP 滑动窗口呢?
滑动窗口协议,是传输层进行流控的一种措施,接收方通过通告发送方自己的窗口大小,从而控制发送方的发送速度,从而达到防止发送方发送速度过快而导致自己被淹没的目的。
TCP 的滑动窗口解决了端到端的流量控制问题,允许接受方对传输进行限制,直到它拥有足够的缓冲空间来容纳更多的数据。
可能这么描述之后,胖友会有点懵逼,那么建议看下面三篇文章,耐心~
《TCP 滑动窗口控制流量的原理》比较易懂的一篇文章。
《网络基本功(八):细说 TCP 滑动窗口》更为详细的一篇文章。
《TCP 协议的滑动窗口具体是怎样控制流量的?》知乎上的讨论,重点看「wuxinliulei」和「安静的木小昊」的回答。特别是后者的,回答很生动形象。
TCP 协议如何来保证传输的可靠性?
TCP 提供一种面向连接的、可靠的字节流服务。其中,面向连接意味着两个使用 TCP 的应用(通常是一个客户和一个服务器)在彼此交换数据之前必须先建立一个 TCP 连接。
在一个 TCP 连接中,仅有两方进行彼此通信。
而字节流服务意味着两个应用程序通过 TCP 链接交换 8bit 字节构成的字节流,TCP 不在字节流中插入记录标识符。
对于可靠性,TCP 通过以下方式进行保证:
数据包校验:目的是检测数据在传输过程中的任何变化,若校验出包有错,则丢弃报文段并且不给出响应,这时 TCP 发送数据端超时后会重发数据。
对失序数据包重排序:既然 TCP 报文段作为 IP 数据报来传输,而 IP 数据报的到达可能会失序,因此 TC P报文段的到达也可能会失序。TCP 将对失序数据进行重新排序,然后才交给应用层。丢弃重复数据:对于重复数据,能够丢弃重复数据。
应答机制:当 TCP 收到发自 TCP 连接另一端的数据,它将发送一个确认。这个确认不是立即发送,通常将推迟几分之一秒。