三次重复的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意味着发生拥塞?的更多相关文章

  1. (转)为什么收到三个重复的ACK意味着发生拥塞?

    三次重复的ACK,可能是丢包引起的,丢包可能是网络拥塞造成的,也可能是信号失真造成的. 三次重复的ACK,也有可能是乱序引起的,而乱序和网络拥塞没有直接关系. 如果就写这两行,感觉什么都没写,接下来的 ...

  2. TCP主动打开 之 第三次握手-发送ACK

    假定客户端执行主动打开,并且已经收到服务器发送的第二次握手包SYN+ACK,在经过一系列处理之后,客户端发送第三次握手包ACK到服务器:其流程比较简单,主要是分配skb,初始化ack包并发送:需要注意 ...

  3. Leetcode(三)无重复字符的最长子串

    3. 无重复字符的最长子串 题目描述 给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度. 示例: 输入: "abcabcbb" 输出: 3 解释: 因为无重复字符的最 ...

  4. 精读JavaScript模式(三),new一个构造函数居然发生了什么?

    一.前言 上个月底,爸爸因为事故突然离世,说心里话,现在看到'去世','爸爸'这样的字眼,眼泪都会忍不住在眼眶打转,还是需要时间治愈.最近也只是零碎的看了下东西,始终沉不下心去读书,直到今天还是决定捡 ...

  5. TCP三次握手第三次握手时ACK丢失怎么办

    Server 端 第三次的ACK在网络中丢失,那么Server 端该TCP连接的状态为SYN_RECV,并且会根据 TCP的超时重传机制,会等待3秒.6秒.12秒后重新发送SYN+ACK包,以便Cli ...

  6. TCP被动打开 之 第三次握手-接收ACK

    假定客户端主动打开,发送syn包到服务器,服务器创建连接请求控制块加入到队列,进入TCP_NEW_SYN_RECV 状态,发送syn+ack给客户端,并启动定时器,等待客户端回复最后一个握手ack: ...

  7. Spring ActiveMQ 整合(三): 确认机制ACK(收到消息后,应该有一个回应也就是确认答复)

    https://blog.csdn.net/dly1580854879/article/details/68490197

  8. TCP基础知识(三)重传、流量控制、拥塞控制

    TCP详解(3):重传.流量控制.拥塞控制…… 数据传输 在TCP的数据传送状态,很多重要的机制保证了TCP的可靠性和强壮性.它们包括:使用序号,对收到的TCP报文段进行排序以及检测重复的数据:使用校 ...

  9. TCP/IP详解(三)

    超时与重传: TCP在发送一个包时,启动一个定时器,如果在定时器溢出之前没有收到ACK,则认为发出的包丢失了,此时会重传丢失的包.这就是超时重传. 其中定时器的时间不是一个固定值,它是根据RTT计算的 ...

随机推荐

  1. (1)PyCharm开发工具安装Flask并创建helloworld程序

    一.环境描述 1.操作系统:windows7 2.编程语言:python3.6 下载地址:https://www.python.org/downloads/windows/ 3.虚拟化环境:virtu ...

  2. 【翻译】Flink Table Api & SQL —Streaming 概念 ——在持续查询中 Join

    本文翻译自官网 :  Joins in Continuous Queries   https://ci.apache.org/projects/flink/flink-docs-release-1.9 ...

  3. Excel如何输入负数

    一般红字发票很少开,以前都是单独把红字发票摘出来放到一行里,然后加减一下,前段时间有个客户因为普票无法报销,改要了专票,因为是电子发票,无法作废,开了张红字.虽然红字很少开,但是想着百度一下如何在ex ...

  4. [LeetCode] 123. Best Time to Buy and Sell Stock III 买卖股票的最佳时间 III

    Say you have an array for which the ith element is the price of a given stock on day i. Design an al ...

  5. linux grep的用法

    linux grep的用法<pre>[root@iZ23uewresmZ ~]# cat /home/ceshis.txtb124230 b034325 a081016 m7187998 ...

  6. sql查询出现1055 this is incompatible with sql_mode=only_full_group_by

    今天在测试服务器上突然出现了这么一个MySQL的问题,同样的代码正式服没有问题,那肯定就是出在了配置上,查了一下原因才明白原来是数据库版本为5.7以上的版本, 默认是开启了 only_full_gro ...

  7. python 之 Django框架(ORM常用字段和字段参数、关系字段和和字段参数)

    12.324 Django ORM常用字段 .id = models.AutoField(primary_key=True):int自增列,必须填入参数 primary_key=True.当model ...

  8. visual studio code 命令行创建发布一个项目

    安装vs core 打开按ctrl+~键打开终端 输入dir看看有什么文件,输入md Test 创建一个文件夹,选择文件后创建一个项目 输入dotnet可以查看信息 执行dotnet --help或者 ...

  9. linq 动态排序 order by

    项目查询数据库使用的是linq 语法,可是后期需要用到不同字段的排序.各种纠结! 在网上找了各种资料 后面才找到两种方法 using System; using System.Collections. ...

  10. Jsp页面显示时间:<fmt>标签问题

    <%@ taglib prefix="fmt" uri="http://java.sun.com/jstl/fmt"%> <%@ taglib ...