首先介绍一下TCP连接建立与关閉过程中的状态TCP连接过程是状态的转换,促使状态发生转换的因素包括用户调用、特定数据包以及超时等具体状态如下所示:
TCP连接的状态转换如下图所示
建立TCP连接需要三次握手而关闭连接则需要四次握手,並且分为主动关闭和被动关闭这是由于TCP连接是全双工的,我关了你的连接并不等于你关了我的连接,因此双方都必须单独进行关闭當一方完成它的数据发送任务后可以发送FIN包来终止这个方向的连接,表明自己不再有数据需要发送;收到FIN包的那一方虽然不能再读取数据但仍能发送数据。以Client主动关闭连接为例:
TCP连接的建立到关闭,需要经历以下状态迁移(假定Client发起连接并主动关闭连接):
在详细了解TCP連接的状态和关闭方式后,我们会发现TIME_WAIT状态是一个坑爹的存在!主动关闭连接的一方在发送最后一个ACK包后无论对方是否收到都会进入TIME_WAIT状態,等待2MSL的时间然后才能释放网络资源。MSL就是Maximum Segment Lifetime(数据包的最大生命周期)是一个数据包能在互联网上生存的最长时间,若超过这个时間则该数据包将会消失在网络中操作系统通常会将2MSL设为4分钟,最低不少于30秒因而TIME_WAIT状态一般维持在30秒至4分钟。这个是TCP/IP协议必不可少的昰TCP/IP设计者设计的,也就是无法解决的TIME_WAIT状态的存在主要有两个原因:
对于Client而言,每个连接都需要占用一个端口而系统允许的可用端口数不足65000个(這也是在TCP参数优化后才能达到)。因此如果Client发起过多的连接并主动关闭(假设没有重用端口或者连接多个Server),就会有大量的连接在关闭後处于TIME_WAIT状态等待2MSL的时间后才能释放网络资源(包括端口),于是Client会由于缺少可用端口而无法新建连接
对Server而言(特别是处理高并发短连接的Server),Server端与Client建立的连接是使用同一个端口的即监听的端口,每个连接通过一个五元组区分包括源IP地址、源端口、传输层协议号(协议类型)、目的IP地址、目的端口,因而在理论上Server不受系统端口数的限制。但是Server对每个端口上的连接数是有限制的,它要使用哈希表记录端口上的每个连接并受到文件描述符的最大打开数的限制。所以如果Server主动关闭连接,同样会有大量的连接在关闭后处于TIME_WAIT状态等待2MSL的时间后才能释放网络资源(包括哈希表上的连接记录和文件描述符),于是Server会由于达到哈希表和文件描述符的限制而无法接受新连接造成性能的急剧下滑,性能曲线会持续产生严重的波动对于这种情况,有三种应对方式:
在学习TCP/IP协议的大头:TCP协议 的过程中遇到了很多机制和知识点,详解中更是用了足足8章的内容介绍它
TCP协议作为 应用层 和 网络层 中间的 傳输层协议,既要为下面的网络层协议保证连接的可靠性(IP协议)弥补不足又要作为 应用层进程向网络层发送数据的中转站(作为多路复用/解複用器)。
这就使得我们在审视TCP这个协议的过程中需要横向和纵向地看待TCP连接:
- 纵向的连接:网络层 和 应用层 之间联系的纽带,协助 应用層 向网络层 转递数据
与此同时,在TCP的学习中我们还需要解答TCP的相关问题:
TCP是如何保障连接的可靠性的?-超时重传的内容
TCP是如何解决网絡拥塞的-各种机制:慢启动,拥塞避免经受时延的ACK···
TCP是如何解决流量控制(目的:提高网络的利用率)的?-窗口机制:拥塞窗口通告窗口···
保证 reliable 的目的是为了解决网络层协议的不足之处:解决数据的丢失重传问题,使得传输数据的连接变得更加可靠;而 control 的目的则是想辦法使得传输的效率更高两者相互影响:
比如我重发数据报的时候会不会造成网络的拥塞?我控制网络拥塞的时候会不会导致传输效率嘚低下我要什么时候控制网络拥塞而不会过度控制 导致我的一些重要信息发送缓慢?我要什么时候发送数据报才不会造成更加严重的网絡拥塞
正是为了解决这些十分纠结的问题,TCP诞生了正是它的伟大和不足,以及为了解决它的不足提出的各种各样的方法使得它具有洣人的魅力。
本文不会过多的抠细节是一篇对 TCP各部分的小结,试图阐述清楚它们之间的关系
众所周知TCP是通过 三次握手 和 四次挥手 来建立/终止一个 client-server TCP连接的。
三次握手 建立起 TCP连接 的 reliable分配初始序列号和资源,在相互确认之后开始数据的传输有 主动打开(一般是client) 和 被动打开(一般昰server)。
四次挥手因为TCP连接是全双工的,数据可以在两个方向上进行传递因此在关闭的时候需要必须单独终止两个方向的数据传输。有 主動关闭(一般是client) 和 被动关闭(一般是server)
既然有三握四挥的机制,那么在它进行的过程中client端 和 server端 就有不同的状态,在SYN报文FIN报文或者昰ack的发送/接收,都会导致状态的转移也就有了TCP状态转移图:
研究清楚这幅图是学习 TCP连接的建立与终止 的关键。
当发送端 接收到 接收端的 FIN并发送最后一个ack之后,发送端从 FIN_WAIT2状态 进入 TIME_WAIT状态
TCP数据报有一个 报文段最大生存时间MSL,它是任何报文段被丢弃前在网络内的最长时间
设置2MSL状态的目的是为了防止以下状态:发送端发送的最后一个ack丢失。设置时间最长为 2MSL 的等待状态保证接收端的定时器超时重传FIN,使得发送端重新发送最后一个ack
假如没有2MSL状态,服务器没有收到最后一个ack向发送端重发一个FIN,此时发送端已经关闭这个FIN有可能被丢失,有可能遲到倘若发送端和接收端 重新使用同一个套接字/插口对(socket):目的端IP地址,源IP地址目的端端口号,源端口号组成的组合 所确定的连接那麼如果说FIN迟到了,并到达发送端有可能异常终止这条连接。
所以我们要求在2MSL等待状态的时候,确定这条连接的插口对(socket)不能被使用也僦是说,不能用于建立新的连接
三种情况发送复位报文段:
需要注意的是 第三种情况:一方异常关闭但是另外一方还不知道,这在の后的保活定时器(keep-alive)有提到
TCP是如何保證数据传输的可靠性的答曰重传定时器。
重传定时器保证了局域网 从发送方到接收方在定时器超时溢出且还没有收到对数据的确认的時候,重新发送数据报并启动一些机制(数据报丢失很可能是因为网络拥塞,为了减缓网络拥塞TCP提供了许多解决网络拥塞的方法,这里提到的是慢启动/拥塞避免)
关于定时器时间的计算,采用了估计 往返时间RTT 和 重传时间RTO 的策略
(1)如果超时没有接收到数据报,RTO 采用 指数退避 嘚方法更新
(2)如果接收到了数据报,定时器首先跟踪往返时间RTT然后根据公式来计算 RTO。公式利用了 均值偏差 和 RTT估计器 来减小计算RTO时因为网絡时延等原因带来的误差
重传定时器的设计有两个原则:一是 发送完如何一个报文,并长期收不到它的确认的时候必须超时;二是 不能过早的超时:即超时的时间设置 不能和 测量的RTT 差太远。
对于定时器RFC有以下四则规则:
(1)发送TCP分段时,如果还没有重传定时器开启那么開启它。
(2)发送TCP分段时如果已经有重传定时器开启,不再开启它
(3)收到一个非冗余ACK时,如果有数据在传输中重新开启重传定时器。
(4)收到┅个非冗余ACK时如果没有数据在传输中,则关闭重传定时器
其中规则3是用于避免过早的重传。
也就是说当发送端一次性发送多个数据報的时候,比如一次性发送 A B C D 四个数据报(暂且不考虑拥塞窗口和通告窗口)当 发送A 的时候,启动重传定时器在收到 A的确认 的时候,重置 重傳定时器这样保证不会出现这样的情况:一次性发送完以上的四个数据报之后,发送端等待的是 对D数据报的确认但是在定时器超时之湔,除了比较早发送的 A B 局域网 从发送方到接收方接收到了对它们的确认之外并没有收到 C 和 D 的确认,这就导致了 不必要的重传
大多数情況下,一个数据报测得的 往返时间RTT 约等于 重传时间
本节将看到TCP对网络的流量控制,和避免网络拥塞的众多机制:
经受时延的确认(接收方) Nagle算法(局域网 從发送方到接收方) 通告窗口(接收方) 拥塞窗口(局域网 从发送方到接收方) 滑动窗口机制(接收方 & 局域网 从发送方到接收方) 慢启动(局域网 从发送方箌接收方) 拥塞避免算法(局域网 从发送方到接收方) 快速重传和快速恢复(局域网 从发送方到接收方) 糊涂窗口综合症的解决方法(接收方 & 局域网 从發送方到接收方)
TCP是怎么样解决这个死循环并提高网络的效率的呢?
- (1)避免过多的ack造成 低速网络(如广域网) 的网络拥塞:经受时延的确认
联系:Nagle算法,避免糊涂窗口综合症的措施(防止小包)
- (2)避免接收方处理过慢,导致接收队列溢出数据丢失:通告窗口
联系:拥塞窗口,滑动窗口机制
经受时延的确认/数据捎带ACK:通常TCP在收到数据的时候,並不马上发送对该数据的确认相反,它推迟发送以便将ACK与需要沿该方向发送的数据一起发送。绝大多数的时延为200ms
在慢速网络 比如广域网上,过多的小包会造成一定的网络拥塞从而导致数据报的丢失,效率低下而如果 接收方TCP 并不采用此机制,即一接收到数据报就发送对它的确认ACK无疑会造成小包数量的剧增,再加上服务器本来就要向局域网 从发送方到接收方发送的数据造成网络拥塞也就并不奇怪叻。
通告窗口:接收方以一个比较慢的速率来处理接收的数据而局域网 从发送方到接收方以一个比较快的速率来发送数据,如果没有一個合理的机制来控制的话势必会造成接收方接收队列的溢出,网络的拥塞以及数据的丢失接收方提供的是 通告窗口,与 经受时延的ACK 或鍺是 数据 一起发送往局域网 从发送方到接收方
联系:滑动窗口机制,通告窗口
- (2)拥塞窗口 -慢启动提供:概要中与(1)一起
联系:滑动窗口机制,通告窗口
- (3)快速重传,快速恢复算法
联系:慢启动拥塞避免等。
联系:经受时延的ACK避免糊涂窗口综合症的措施。
慢启动:如果局域网 从发送方到接收方┅开始就向接收方发送多个报文段直到达到接收方的通告窗口为止,很容易造成中间路由器的缓存溢出耗尽存储启动空间,从而造成網络拥塞
慢启动的工作方法是观察到 新分组进入网络的速率 = 另外一端确认分组的速率 来进行工作的。
慢启动为局域网 从发送方到接收方增添了:拥塞窗口初始值为1,每接收到一个ack就增加1发送数据报的数量取决于 min{拥塞窗口,通告窗口}
但是,慢启动一点也不慢它的拥塞窗口的增长方式是 指数型的。这样到了后期 拥塞窗口 必然会超过 通告窗口也就达不到控制的效果了。
于是乎我们引入了 拥塞避免算法。
拥塞避免算法:当拥塞窗口增大到一定程度的时候我们采用拥塞避免算法,而不是慢启动慢启动和拥塞避免算法之间的界限 我们稱之为 ssthresh(16个报文段,也就是65535字节拥塞窗口的大小)。
拥塞窗口算法的实现:每收到一个ack拥塞窗口增加1/cwnd,这是一种加性增长放缓了慢启动嘚指数增长。
慢启动和拥塞避免的工作过程:教材P235.
慢启动与拥塞避免的可视化描述:
快速重传快速恢复算法:我们并不知道 一个重复的ACK昰由一个丢失报文段引起的,还是由于仅仅出现了几个报文段的重新排序因此我们必须等待少量的重复ACK的到来。如果一连串收到三个重複的ACK那么基本可以确定是数据报丢失引起的,那么此时网络很有可能已经拥塞需要采取 慢启动或者是拥塞避免的措施 来控制网络拥塞。
在连续收到三个重复的ACK之后我们不用等到定时器溢出,直接进行重传这就是快速重传算法。接下来执行的 并不是 慢启动 而是 拥塞避免这就是快速恢复算法。
我们不想进入慢启动的原因是因为在收发两端仍然有流动的数据,我们并不想使用慢启动从而造成数据流嘚突然减少。
快速重传 快速恢复算法的工作过程:教材P237.
Nagle算法:局域网 从发送方到接收方用于防止小包的措施具体原因与 接收方TCP的 经受时延的ACK 一样:避免慢速网络的网络拥塞。
该算法要求一个TCP连接上 最多只能有一个 未被确认的小分组这导致了局域网 从发送方到接收方数据嘚积累:在确认到达之前不允许发送小分组,相反TCP积累这些小分组并在确认到达的时候“一股脑儿”以一个数据报的形式发送出去。
优樾之处在于:确认到达的越快数据发送的也就越快。它是自适应的
- 滑动窗口机制:局域网 从发送方到接收方TCP 的 拥塞窗口 与 接收方TCP 的 通告窗口 的共同作用。作用于发送端
- 糊涂窗口综合症 与 局域网 从发送方到接收方TCP 的 Nagle算法 和 接收方TCP 的 经受时延的ACK 有直接的关系。
首先谈谈 滑动窗口机制它的可视化表示如下图:
接收方 鉴于自身接收数据的快慢,向局域网 从发送方到接收方提供 通告窗口以实现對发送端发送流量的控制,这个通告窗口就是上图中的 提供的窗口
局域网 从发送方到接收方 根据接收到数据报的情况,基于避免网络拥塞的慢启动算法提供了拥塞窗口,即上图中 发送但未被确认
当局域网 从发送方到接收方发送的数据 被成功确认的时候,滑动窗口的左沿向右移动;同时根据接收方新发送的通告窗口右沿也向右移动。移动的距离是由 返回的确认号 与 发送端缓存的 目前第一个尚未被确认嘚数据报的初始序号 的差值所决定
滑动窗口机制,即体现了 接收方根据自身情况对局域网 从发送方到接收方的流量控制(通过通告窗口)避免了局域网 从发送方到接收方一次性发送过多的数据导致读取数据缓慢的接收方缓存溢出;又体现了 局域网 从发送方到接收方TCP对网络拥塞的监视,以及避免拥塞的策略(通过慢启动算法 提供的 拥塞窗口)
但是,接收方对局域网 从发送方到接收方的流量控制 同时也会带来一些鈈好的东西就是我们接下来要引述的 糊涂窗口综合症 了。
由于接收方处理数据十分缓慢往往在一个数据报往返时间RTT内处理不了多少数據,这就导致了接收端经常会通告一些小窗口这是我们不希望看到的:在前面有提到,过多的小包会加剧慢速网络的网络拥塞程度这僦是 糊涂窗口综合症。
由于接收方可以通告一个小的窗口局域网 从发送方到接收方也可以发送小的数据,因此 避免糊涂窗口综合症的对筞也是从 对局域网 从发送方到接收方 和 对接收方 两个方面着手的:
(1)对局域网 从发送方到接收方(在满足以下条件之一的情况下发送数据)
- 可以發送一个满长度的数据报即一个MSS长度的数据报。
- 可以发送至少是通告窗口一半的数据
- 可以发送任何数据但是不希望接收ACK(前面还有未确认嘚报文) 或者该连接上不能使用Nagle算法
- 接收方不通告小的窗口(特例:教材P249,防止滑动窗口右沿左移)并且一般不通告比目前的接收状况 即窗ロ 更大的大小。除非 接收方应用进程接收了MSS大小的数据或者处理了接收方一半缓存大小的数据。
糊涂窗口综合症的解决方法与局域网 從发送方到接收方TCP的Nagle算法,和接收方的经受时延的ack是TCP用于避免慢速网络(WAN)网络拥塞的策略。
通过角度一对于局域网 从发送方到接收方和接收方各自以及共有的流量控制及避免网络拥塞的策略进行了一个归纳
有我们开头的四个问题:
- TCP是怎么样知道发生了数据报丢失?
- TCP怎么样处理网络拥塞
- TCP怎么样控制重传的时间 从而不会引起过度的不必要的重传?
- TCP怎么样均衡 控制网络拥塞 以及 传输效率
以及这个死循环:网络拥塞 -> 数据报丢失 -> 重传
这个死循环很大程度的导致了传输数据效率的低下,于是乎TCP必然要采取一定的措施来制止这个死循环的發生。
那么我们把这四个问题 和 这个死循环结合起来根据上文的内容来解答他们。
(1)网络拥塞既然TCP知道可能会出现网络拥塞,那么接收方和局域网 从发送方到接收方的TCP肯定要想办法避免它和解决它
避免它:慢启动算法 和 拥塞避免算法,慢启动所提供的拥塞窗口;针对慢速网络:Nagle算法经受时延的ack,避免糊涂窗口综合症的措施
解决它:当拥塞发生的时候,我们希望降低分组进入网络的传输速率拥塞避免算法起到了很好的处理丢失分组的方法,在教材的P235详细说明了拥塞避免算法在拥塞发生的时候所采取的措施(启用慢启动设置ssthresh等)。
(2)数据報丢失网络拥塞造成了数据报丢失,局域网 从发送方到接收方怎么样知道数据报丢失
处理数据报丢失的方法是 (3)重传,那么局域网 从发送方到接收方什么时候重传不会造成重传风暴 导致网络拥塞
TCP 在 发送数据的效率 和 减缓网络拥塞 是怎么样均衡的?
局域网 从发送方到接收方是如何知道数据报丢失的
-重传定时器超时,或者是局域网 从发送方到接收方接收到了三个重复的ack;前者重发数据报并利用指数退避更噺RTO后者立即重发数据报,进入快速重传和快速恢复
准确的来说,重传定时器超时所估计的网络拥塞比接受到的三个重复的ack所估计的网絡拥塞更加严重:收到三个重复的ack有可能是因为数据报的错序导致的说明后面的数据报接收方有收到,就进入快速重传快速恢复状态;洏重传定时器超时估计起来就严重的多了网络拥塞程度已经严重到丢失大量数据的阶段了,因此必须使局域网 从发送方到接收方重新进叺调整网络拥塞的状态:慢启动或者拥塞避免
什么时候重传 不会造成进一步的拥塞?
-控制重传时间的 是重传定时器TCP利用对往返时间RTT的測量跟踪路由器和网络流量的变化,利用往返时间RTT的估计器以及均值偏差来确定重传的时间最大程度的降低了估计的误差,并且利用RFC定義的重传定时器的四个原则保证了它不会过早的重传从而造成不必要的重传。
TCP是怎么样均衡控制网络拥塞 和 传输效率的
-利用滑动窗口機制,以及慢启动对拥塞窗口的“指数型增长” 和 拥塞避免对拥塞窗口的“加性增长”尽可能的利用带宽,同时也减小网络拥塞发生的鈳能滑动窗口机制的拥塞窗口是局域网 从发送方到接收方根据其对网络拥塞的估计(利用RTT) 避免中间路由缓存的溢出 所采取的流量控制措施;而通告窗口则是 接收方 根据自身进程接收数据的快慢,以及在该连接上可用缓存的大小采取的流量控制措施。 与此同时避免网络拥塞的 慢启动 和 拥塞避免 也提供了利用网络带宽 提高网络效率的方法:每接收到一个ack,就增加拥塞窗口的大小
这样,均衡地控制了网络拥塞 也保证了一定的传输效率
慢启动和拥塞避免 是避免网络拥塞,解决网络拥塞的方法它们作用于拥塞窗口,使在不同的网络条件下(拥塞或者不拥塞)尽可能的利用带宽
这就是TCP中的control,内容既复杂又相互联系但是需要抓住本质的两点来分析:1)控制流量,避免网络拥塞 2)控制傳输数据的效率
TCP是一个巨复杂的协议因为怹要解决很多问题,而这些问题又带出了很多子问题和阴暗面所以学习TCP本身是个比较痛苦的过程,但对于学习的过程却能让人有很多收獲关于TCP这个协议的细节,我还是推荐你去看的《》(当然你也可以去读一下以及后面N多的RFC)。另外本文我会使用英文术语,这样方便你通过这些英文关键词来查找相关的技术文档
之所以想写这篇文章,目的有三个
所以本文不会面面俱到,只是对TCP协议、算法和原理的科普
我本来只想写一个篇幅的文章的,但是TCP真TMD的复杂比C++复杂多了,这30多年来各种优化变种争论和修改。所以写着写着僦发现只有砍成两篇。
废话少说首先,我们需要知道TCP在网络OSI的七层模型中的第四层——Transport层IP在第三层——Network层,ARP在第二层——Data Link层在第二层上的数据,我们叫Frame在第三层上的數据叫Packet,第四层的数据叫Segment
首先,我们需要知道我们程序的数据首先会打到TCP的Segment中,然后TCP的Segment会打到IP的Packet中然后再打到以太网Ethernet的Frame中,传箌对端后各个层解析自己的协议,然后把数据交给更高层的协议处理
接下来,我们来看一下TCP头的格式
你需要注意这么几点:
关于其它的东西,可以参看下面的图示
其实网络上的传输是没有连接的,包括TCP也是一样的而TCP所谓的“连接”,其实只不过是在通讯的双方维护一个“连接状态”让它看上去好像有连接一样。所以TCP的状态变换是非常重要的。
下面是:“TCP协议嘚状态机”() 和 “TCP建链接”、“TCP断链接”、“传数据” 的对照图我把两个图并排放在一起,这样方便在你对照着看另外,下面这两個图非常非常的重要你一定要记牢。(吐个槽:看到这样复杂的状态机就知道这个协议有多复杂,复杂的东西总是有很多坑爹的事情所以TCP协议其实也挺坑爹的)
很多人会问,为什么建链接要3次握手断链接需要4次挥手?
另外有几个事情需要注意一下:
你可以看到SeqNum的增加是和传输嘚字节数相关的。上图中三次握手后,来了两个Len:1440的包而第二个包的SeqNum就成了1441。然后第一个ACK回的是1441表示第一个1440收到了。
TCP要保证所有嘚数据包都可以到达所以,必需要有重传机制
注意,接收端给发送端的Ack确认只会确认最后一个连续的包比如,发送端发了1,2,3,4,5一共伍份数据接收端收到了1,2于是回ack 3,然后收到了4(注意此时3没收到)此时的TCP会怎么办?我们要知道因为正如前面所说的,SeqNum和Ack是以字節数为单位所以ack的时候,不能跳着确认只能确认最大的连续收到的包,不然发送端就以为之前的都收到了。
一种是不回ack死等3,当局域网 从发送方到接收方发现收不到3的ack超时后会重传3。一旦接收方收到3后会ack 回 4——意味着3和4都收到了。
但是这种方式会有仳较严重的问题,那就是因为要死等3所以会导致4和5即便已经收到了,而局域网 从发送方到接收方也完全不知道发生了什么事因为没有收到Ack,所以局域网 从发送方到接收方可能会悲观地认为也丢了,所以有可能也会导致4和5的重传
这两种方式有好也有不好。第一种会节省带宽但是慢,第二种会快一点泹是会浪费带宽,也可能会有无用功但总体来说都不好。因为都在等timeouttimeout可能会很长(在下篇会说TCP是怎么动态地计算出timeout的)
于是,TCP引叺了一种叫Fast Retransmit 的算法不以时间驱动,而以数据驱动重传也就是说,如果包没有连续到达,就ack最后那个可能被丢了的包如果局域网 从發送方到接收方连续收到3次相同的ack,就重传Fast Retransmit的好处是不用等timeout了再重传。
比如:如果局域网 从发送方到接收方发出了12,34,5份数据第一份先到送了,于是就ack回2结果2因为某些原因没收到,3到达了于是还是ack回2,后面的4和5都到了但是还是ack回2,因为2还是没有收到于昰发送端收到了三个ack=2的确认,知道了2还没有到于是就马上重转2。然后接收端收到了2,此时因为34,5都收到了于是ack回6。示意图如下:
Fast Retransmit只解决了一个问题就是timeout的问题,它依然面临一个艰难的选择就是重转之前的一个还是重装所有的问题。对于上面的示例来说是偅传#2呢还是重传#2,#3#4,#5呢因为发送端并不清楚这连续的3个ack(2)是谁传回来的?也许发送端发了20份数据是#6,#10#20传来的呢。这样发送端很有鈳能要重传从2到20的这堆数据(这就是某些TCP的实际的实现)。可见这是一把双刃剑。
Retransmit的ACKSACK则是汇报收到的数据碎版。参看下图:
这样在发送端就可以根据回传的SACK来知道哪些数据到了,哪些没有到于是就优化了Fast Retransmit的算法。当然这个协议需要两边都支持。在 Linux下可以通過tcp_sack参数打开这个功能(Linux 2.4后默认打开)。
这里还需要注意一个问题——接收方Reneging所谓Reneging的意思就是接收方有权把已经报给发送端SACK里的数据給丢了。这样干是不被鼓励的因为这个事会把问题复杂化了,但是接收方这么做可能会有些极端情况,比如要把内存给别的更重要的東西所以,局域网 从发送方到接收方也不能完全依赖SACK还是要依赖ACK,并维护Time-Out如果后续的ACK没有增长,那么还是要把SACK的东西重传另外,接收端这边永远不能把SACK的包标记为Ack
注意:SACK会消费局域网 从发送方到接收方的资源,试想如果一个攻击者给数据局域网 从发送方到接收方发一堆SACK的选项,这会导致局域网 从发送方到接收方开始要重传甚至遍历已经发出的数据这会消耗很多发送端的资源。详细的东西請参看《》
Duplicate SACK又称D-SACK其主要使用了SACK来告诉局域网 从发送方到接收方有哪些数据被重复接收了。里有详细描述和示例下面举几个例子(來源于)
D-SACK使用了SACK的第一个段来做标志,
示例一:ACK丢包
下面的示例中丢了两个ACK,所以发送端重传了第一个数据包(),于是接收端发现重复收到于是回了一个SACK=,洇为ACK都到了4000意味着收到了4000之前的所有数据所以这个SACK就是D-SACK——旨在告诉发送端我收到了重复的数据,而且我们的发送端还知道数据包没囿丢,丢的是ACK包
示例二,网络延误
下面的示例中网络包()被网络给延误了,导致局域网 从发送方到接收方没有收到ACK而后媔到达的三个包触发了“Fast Retransmit算法”,所以重传但重传时,被延误的包又到了所以,回了一个SACK=因为ACK已到了3000,所以这个SACK是D-SACK——标识收到叻重复的包。
这个案例下发送端知道之前因为“Fast Retransmit算法”触发的重传不是因为发出去的包丢了,也不是因为回应的ACK包丢了而是因为網络延时了。
可见引入了D-SACK,有这么几个好处:
1)可以让局域网 从发送方到接收方知道是发出去的包丢了,还是回来的ACK包丢了
2)是不是自己的timeout太小了,导致重传
3)网络上出现了先发的包后到的情况(又称reordering)
4)网络上是不是把我的数据包给复制了。
知道这些东西可以很好得帮助TCP了解网络情况从而可以更好的做网络上的流控。
好了上篇就到这里结束了。如果你觉得我写嘚还比较浅显易懂那么,欢迎移步看下篇《》