【转】三个重复的ACK意味着发生拥塞?
三次重复的ACK,可能是丢包引起的,丢包可能是网络拥塞造成的,也可能是信号失真造成的。
三次重复的ACK,也有可能是乱序引起的,而乱序和网络拥塞没有直接关系。
如果就写这两行,感觉什么都没写,接下来的文字详细解释这两行文字。
TCP背景知识 客户端有1M的文件需要上传到服务器上,问题来了,这个大文件能否用一个TCP报文传输?
肯定不能啊,因为网络路径有最大传输单元(MTU = 1500)的限制,所以IP报文不能大于1500字节,那怎么办啊?
那就让TCP将1M砍成N个1460字节的segment,这里N=685,问题又来了,这685个TCP报文如果发送方不编号,到达接收方之后,接收方依靠什么方法知道谁是第1个segment,谁是第2个segment。。。谁又是第685个segment?
为何要编号呢?不编号难道不可以吗? 比如发送方只要将685个segment按序发送, 1、2、3、4、5。。。681、682、683、684、685,这些segment排着队伍,到达终点顺序也应该是1、2、3。。。683、684、685,然后再将685个segment按序拼接在一起,就会复原成1M 字节的文件。
理想很丰满,现实很骨感,现实会把这个理想击打成粉粹。现在作者提出三个问题,读者分析一下如何解决: (1) 乱序 假如第4、5 segment在传输过程中发生了乱序,即5比4先到达,接收方拼接的文件将为“12354。。。”,拼接文件就不是发送方的文件了,而是一个完全没有意义的废文件了,拼了老命吭哧吭哧,结果到对方却是废文件,这是无法接受的。
(2) 丢包 假如第4个segment在传输过程中不幸丢了,接收方无法完整地拼接出原始文件。
(3) 重复包 假如第4个segment在传输过程被网络设备多发送了一次,接收方拼接出的文件将是“123445。。”
如果TCP真是这么脆弱不堪,压根不会垄断可靠传输层协议,也不会有今天的地位。
那么TCP是如何解决以上三个问题的?
很简单,就两个字:编号!
编号可以解决以上三个常见问题,详细解释见下文。
乱序 接收方发现5先到,而4没有到,TCP先将5用仓库缓存下来,耐心等待4的到来,4到达之后,再按照顺序将4、5重写排列好,这很好理解吧?
丢包 接收方对于接收到的segment,会发送一个确认ACK,告诉发送方已经成功接收的编号数字,对于迟迟没有确认的segment 4,发送方的闹钟(timer)一响(timeout),会自动重传segment 4,最终接收方也可以收到segment 4。
同学们肯定会说,由于segment 5、6、7没有丢,可能早就到达了接收方,在segment 4重传到达之前,TCP如何处理它们?
也是用仓库临时堆放一下,等4到来之后,就可以按照4567。。。的顺序让应用程序取走数据了,这个和快递公司的工作模式很相似。
重复包 既然segment 编号了,接收方发现segment 4已经收到过,再次收到segment 4已经没有任何意义了,直接丢弃就可以了。
TCP确认机制 发送方发送segment 1,接收方收到之后需要ACK确认,这里需要敲黑板提醒还在睡觉同学的注意,ACK确认号是多少?
ACK = 2 ,什么意思呢? 意思是说,segment 1已经成功接收,寡人等待segment 2的到来。每次写到这里,都会想起中学语文课本里那句经典名言:让暴风雨来得更猛烈些吧! 亚当夏娃仍玉米棒子的故事正是受这句名言的启发。
如果发送方发送的segment是“1、2、3、4、5、6”,那么接收方应该如何ACK确认呢? 同学们会说,那不是很简单吗? 收到6个segment,那就发6次ACK,应该是“2、3、4、5、6、7”,当接收方接到ACK =7,就意味着编号7前面所有segment都成功接收,在这里就是“1、2、3、4、5、6”都成功接收了。
问题是ACK的次数有点多,接收方发送一次ACK耗费CPU,接收方接到一次ACK也耗费CPU,另外ACK报文对网络也是一个小小的负担。
于是RFC建议优化ACK方法,每收到2个segment,发送一次ACK,这样就会将ACK数目减半,Good Idea!
那么接收方可以这样ACK :“3、5、7。。。”,当发送方接收到ACK=7,表明segment 1、2、3、4、5、6已经到了。
问题来了,如果发送方只有一个segment发送,按照以上规则,接收方接收2个segment才发送一个ACK,既然只有一个segment,那接收方的ACK会不会永远也发不出?
会的,机器是一根筋认死理,这里会造成通信的死锁(deadlock)。但人是活的,只要帮助TCP启动一个定时器就好,只要闹钟响了(timeout)而第二个segment还没有到,这时就顾不了那么多,直接发ACK就好。
TCP 慢启动(slow start)就是先发segment 1,直到接到对方ACK了,才会发segment 2、3。有了这个定时器,就可以避免TCP慢启动期间的通信死锁。
信息不对称 假如发送方发送segment “1234567”,接收方接到的是“1235”,接收方接到5的那一瞬间,知道4有可能丢了,也有可能乱序了,至于是哪种情况,接收方无从知晓。 但发送方对于segment 4的状态是完全空白的,既然接收方知道多一点,为什么不把这个信息同步给发送方呢?
通过什么方法把消息同步给发送方呢? ACK =4
有同学会迷惑不解,明明收到的是5,应该ACK= 6,为何这里是4?
ACK=6 是什么意思?
表示 “12345”都成功接收,问题是4收到了吗?没有啊!所以只能ACK=4。
稍后,接收方所有接收到的segment为 “12356”,接收方如何做? ACK=4
再稍后,接收方所有接收到的segment为 “123567”,接收方如何做? ACK =4
发送方一直记录自己重复收到某个ACK的次数,Duplicated ACK(4) =3,此时发送方意识到segment 4有可能丢了,此时应该立马主动将segment 4重传出去,而不要被动等待segment 4的重传定时器超时再重传segment 4。
由于这种依赖外界刺激的重传方法比超时重传更快、更及时,美其名曰:快速重传(Fast Re-transmit)。
当重传的segment 4到达接收方时,终于将不连续的segment流 “123567” 修复(Restore)成连续的segment流 “1234567”,通常称这种主动修复字节流的方法为快速修复(Fast Restore)。两者合在一起统称Fast Re-transmit / Fast Restore。
上文说的外界刺激,就是发送方连续收到三次duplicated ACK,立马启动Fast Re-transmit / Fast Restore机制。
如果上文中的接收方所有接收到的segment 不是“123567”,而是”123564”,此时就是乱序的发生,接收方会重新排序成”123456” ,接收方发送ACK =7即可,segment是连续的,无需修复。
在这种情况下,发送方只接到了两次duplicated ACK =4,无需启动Fast Retransmit / Fast Restore机制,因为接收方已经成功修复。
总结一下
没有Fast Re-transmit / Fast Restore机制,TCP完全可以凭借超时重传来完成可靠传输,由于是被动地等待,所以传输效率低下。
FastRe-transmit / Fast Restore机制,使得TCP能够快速地通过三次重复的ACK,推测报文有丢失的可能,进而主动重传,传输效率更高。
补充阅读
论修复不连续segment的重要性
上文中的segment 4只要不到达接收方,即使segment 5、6、7。。。早已到达,也只能滞留在接收方的仓库(Receive Buffer)里,而不能被应用程序取走。
Receive Buffer和Advertised Window Size是直接相关的,接收方的receive buffer被占用,势必通告给发送方的window size就会变小,影响发送方CWND,进而影响发送方的发送速率。
Delivery Rate = CWND / SRTT
其中
SRTT = Smooth Round Trip Time,平均往返时间延迟
CWND = Congestion Window,发送方拥塞窗口大小,和接收方的Advertised Window Size有直接关联
Delivery Rate,发送方的发送速率
所以在SRTT不变的前提下,只要CWND变小,发送速率就会下降。
不连续的segment会严重影响TCP的传输效率。而快速修复这种不连续,会释放掉占用的仓库空间,会加快发送方的传输效率。 --------------------- 作者:牛小可 来源:CSDN 原文:https://blog.csdn.net/niukeming/article/details/80779582 版权声明:本文为博主原创文章,转载请附上博文链接!
【转】三个重复的ACK意味着发生拥塞?的更多相关文章
- (转)为什么收到三个重复的ACK意味着发生拥塞?
三次重复的ACK,可能是丢包引起的,丢包可能是网络拥塞造成的,也可能是信号失真造成的. 三次重复的ACK,也有可能是乱序引起的,而乱序和网络拥塞没有直接关系. 如果就写这两行,感觉什么都没写,接下来的 ...
- TCP主动打开 之 第三次握手-发送ACK
假定客户端执行主动打开,并且已经收到服务器发送的第二次握手包SYN+ACK,在经过一系列处理之后,客户端发送第三次握手包ACK到服务器:其流程比较简单,主要是分配skb,初始化ack包并发送:需要注意 ...
- Leetcode(三)无重复字符的最长子串
3. 无重复字符的最长子串 题目描述 给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度. 示例: 输入: "abcabcbb" 输出: 3 解释: 因为无重复字符的最 ...
- 精读JavaScript模式(三),new一个构造函数居然发生了什么?
一.前言 上个月底,爸爸因为事故突然离世,说心里话,现在看到'去世','爸爸'这样的字眼,眼泪都会忍不住在眼眶打转,还是需要时间治愈.最近也只是零碎的看了下东西,始终沉不下心去读书,直到今天还是决定捡 ...
- TCP三次握手第三次握手时ACK丢失怎么办
Server 端 第三次的ACK在网络中丢失,那么Server 端该TCP连接的状态为SYN_RECV,并且会根据 TCP的超时重传机制,会等待3秒.6秒.12秒后重新发送SYN+ACK包,以便Cli ...
- TCP被动打开 之 第三次握手-接收ACK
假定客户端主动打开,发送syn包到服务器,服务器创建连接请求控制块加入到队列,进入TCP_NEW_SYN_RECV 状态,发送syn+ack给客户端,并启动定时器,等待客户端回复最后一个握手ack: ...
- Spring ActiveMQ 整合(三): 确认机制ACK(收到消息后,应该有一个回应也就是确认答复)
https://blog.csdn.net/dly1580854879/article/details/68490197
- TCP基础知识(三)重传、流量控制、拥塞控制
TCP详解(3):重传.流量控制.拥塞控制…… 数据传输 在TCP的数据传送状态,很多重要的机制保证了TCP的可靠性和强壮性.它们包括:使用序号,对收到的TCP报文段进行排序以及检测重复的数据:使用校 ...
- TCP/IP详解(三)
超时与重传: TCP在发送一个包时,启动一个定时器,如果在定时器溢出之前没有收到ACK,则认为发出的包丢失了,此时会重传丢失的包.这就是超时重传. 其中定时器的时间不是一个固定值,它是根据RTT计算的 ...
随机推荐
- react项目中element的DatePicker回显
element的DatePicker获取value的时候是日期对象如下,可以提交的时候查看参数 2019-06-30T17:02:02.000Z 如果是console.log打印出来的话,是这样的 ...
- 导入一个eclipse的java项目到IDEA报Cannot find JDK '1.7' for module 'TEST'
解决办法: 右键你的项目--------------->OPen module settings 将dependencies里面的module sdk改成你安装的java版本就可以了(比如我电脑 ...
- jmap使用
今天写的服务在处理大文件是出现Java heap space错误,因此结识了jmap jmap是JDK自带的一个工具,可以做jvm性能调优 可以生成dump文件,查询finalize执行队列.Java ...
- JIRA学习
Jira是Atlassian公司出品的一款事务管理软件.无论是“需求”,还是“BUG”,或是“任务”,都是“事务”的一种,所以Jira可以胜任非常多的角色:需求管理.缺陷跟踪.任务管理等等……因为Ji ...
- watchdog监控文件变化使用总结——转载
原文链接地址:https://blog.csdn.net/xufive/article/details/93847372 概述 首先声明,本文讨论的 watchdog,不是单片机里的 watchdog ...
- 屏蔽组合键[CTRL+N]
https://www.cnblogs.com/gaodu2003/archive/2011/05/05/2037229.html …… const _KeyPressMask=$80000000; ...
- java.IO.EOFException异常
错误代码为: 43 boolean booleanResult = dis.readBoolean();//dis为DateInputStream的实例 44 System.out.println(b ...
- 基于OpenCV制作道路车辆计数应用程序
基于OpenCV制作道路车辆计数应用程序 发展前景 随着科学技术的进步和工业的发展,城市中交通量激增,原始的交通方式已不能满足要求:同时,由于工业发展为城市交通提供的各种交通工具越来越多,从而加速了城 ...
- springboot 配置elasticsearch Java High Rest Client
前提声明 在新版本的spring boot中逐渐放弃了对Spring Data Elasticsearch的支持,所以不推荐使用,使用ES官方推出的Java High Rest Client. 引入依 ...
- CentOS7 修改Jenkins以root用户运行
修改Jenkins以root用户运行,这在正式环境中是不可取的,但在自己的测试环境中就无所谓了啦,怎么方便怎么来. 1. 修改Jenkins配置文件1.1 修改$JENKINS_USER打开jenki ...