TCP协议要点和难点全解

原创
小哥 2年前 (2023-05-25) 阅读数 73 #大杂烩

转自:http://www.codeceo.com/article/tcp-diffcult.html

说明:

  • 1).本文以TCP的发展历程解析容易引起混淆,误会的方方面面
  • 2).本文不会发布大量的源代码,其中大部分以文本形式描述。我相信文本看起来比代码更容易
  • 3).针对对象:对TCP我们已经有人有全面的了解。因为本文不会解析TCP标题中的每个字段或3第二次握手的细节不会解释慢启动和快速重传的定义
  • 4).除了《TCP/IP详解》( 卷一卷二 )以及《 Unix网络编程 》以及Linux除了源代码之外,学习互联网的更好资源是RFC
  • 5).本文提供了一个大纲。如果您想了解更多详情,请直接参考RFC
  • 6).辗转反侧,终于找到了这份备忘录,而这篇文章就是根据这份备忘录文档的修改而来的。

1.网络协议设计

ISO提出了OSI分层网络模型是理论上的,TCP/IP最后,实现分层协议模型,每层对应一组网络协议,完成一组特定的功能。这组网络协议被其底层重用和取消重用。这是分层模型的本质,其中所有逻辑最终都被编码为电缆或电磁波。

分层模型是很好理解的但是,对于每一层的协议设计却不是那么容易。TCP/IP该协议的美妙之处在于,随着层次结构的向上移动,它变得更加复杂。我们将网络定义为相互连接的设备,其基本功能仍然是“端到端”通信。但是,希望相互通信的设备不一定需要“直接”连接在一起,因此一些中间设备不可避免地负责转发数据。因此,在连接这些中间设备的电缆上运行的协议被定义为链路层协议。其实,所谓的链路其实就是源站设备和一个设备,通过一根线线端接到另一个设备。我们将链接称为“ 一跳 ”。因此,端到端网络包含“许多跃点”。

2.TCP和IP协议

终止于IP协议,我们已经可以完成端到端的通信了,为什么还需要它TCP协议?这是一个问题,一旦我们理解了它,我们就可以理解TCP为什么协议会变成现在这样,为什么这么“复杂”,为什么这么简单。

顾名思义,TCP的功能是传输控制,即控制端到端传输。那么为什么这个控件不可用IP在协议中实现。答案很简单,会增加IP协议的复杂性,以及IP该协议要求简单。这是什么原因呢?

首先我们认识一下为何IP协议是沙漏的细长部分。它的下层由各种链路层协议组成,这些协议提供截然不同和截然不同的语义。为了互连这些异构网络,我们需要一个网络层协议,该协议必须至少提供一些自适应功能。此外,它不能提供太多的“有保障的服务”,因为上层的保证依赖于下层更强的约束保证,你永远不可能处于100M在吞吐量链路上实现IP协议保证1000M吞吐量

IP协议设计为分组转发协议,每一跳都要经过一个中间节点,路由的设计是TCP/IP网络的另一大创举,这样,IP协议不需要方向性,路由信息不再与协议本身紧密关联。他们只依靠IP地址来关联,因此,IP协议更简单。作为中间节点,路由器不能太复杂,这涉及到成本问题。因此,路由器只负责路由和转发数据包。

因此,传输控制协议不可避免地需要在端点实现。在我们的详细讨论中TCP在达成协议之前,首先看看它不能做什么,因为IP该协议不提供保证,TCP它也不能提供依赖IP较低级别的链路(如带宽和延迟)的保证由链路层决定。因为IP无法修补协议,TCP它也不能,但它可以纠正起点IP层的一些“非保证属性”包括IP层不可靠性,IP层的不按顺序,IP非定向图层/无连接。

总结本节, TCP/IP模型 从下往上,功能增加,需要实现的设备减少,然而设备的复杂性却在增加,这样保证了成本的最小化,至于性能或者因素,靠软件来调节吧,TCP协议就像这个软件,其实从一开始就,TCP不考虑性能、效率或公平性,正是考虑了这些考虑,TCP协议变得更加复杂。

3.TCP协议

这是一个纯软件协议,为什么它设计有两个端点,如上一节所述TCP该协议还穿插了一些简短的讨论。

3.1.TCP协议

准确地说,TCP协议有两重身份,作为网络协议,它弥补了IP该协议尽最大努力弥补缺点,实现消息的连接、可靠传输和顺序到达。作为主机软件,它与UDP而左右传输层协议隔离主机服务和网络,可以看作是多路复用/解复用器,多路复用来自多个主机进程的数据/解复用到IP层。
可见,从任何角度,TCP两者都作为接口存在,作为网络协议,与TCP接口、实现TCP多路复用的控制逻辑/解复用器,连接到下层IP协议接口实现协议栈的功能,是分层网络协议模型的基本定义(两种类型的接口,一种具有较低级别的接口,另一种具有对等级接口)。

我们习惯使用TCP作为协议栈的顶部,与其将应用层协议视为协议栈的一部分,这部分是因为应用层TCP/UDP解复用后,出现了一个复杂的情况,应用层协议以完全不同的方式解释,应用层协议习惯于使用类似的方法ASN.1标准包装反映TCP多路复用协议/解复用器的重要性在于,由于它们与解复用器的直接接口,它们可以很容易地被应用程序控制,从而实现不同的传输控制策略TCP被设计离应用程序不太远的原因之一。

总之, TCP有四个关键点:连接、可靠传输、数据到达和端到端流量控制。 注意,TCP设计时,只有这四点是有保证的。虽然这个时候可能会有一些问题,很简单,但更大的问题很快就会出现,使得有必要考虑和IP与网络相关的东西,如公平和效率,增加了拥塞控制TCP它已经成为现在的样子。

3.2.连接、可靠的传输和数据按顺序到达TCP

IP协议没有方向,数据报的传输只能通过路由到达另一端。因此,它是逐跳到达另一端的。只要有一跳没有到达另一端的路由,数据传输就会失败。事实上,路由也是互联网的核心之一。IP该层提供的核心基本功能是双重的:第一是地址管理,第二是路由。TCP利用了IP路由是一个简单的功能,因此TCP无需考虑路由,这是将其设计为端到端协议的另一个原因。

既然IP我们已经可以尽最大努力确保单个数据报到达相反的一端,因此TCP您可以在此尽力而为的网络上实现其他更严格的控制功能。TCP对于未连接IP网络通信增加了连接性,确认已发送数据的状态,并确保数据的顺序。

3.2.1.有连接

这是TCP的基本,因为后续的传输的可靠性以及数据序列都依赖于一条连接,这是最简单的实现方式,因此TCP设计为基于流的协议,因为TCP需要提前建立连接,之后传输多少数据并不重要,只要能够识别来自同一连接的数据即可。
疑难杂症1:3次握手和4次挥手
TCP使用3第二次握手建立连接,初始化传动可靠性和数据序列的必要信息。此信息包括两个方向的初始序列号,确认号由初始序列号生成3第二次握手是因为3次握手已经准备好了传动可靠性以及数据序列所必要的信息,该握手的第3次实际上并不是需要单独传输的,完全可以和数据一起传输。
TCP使用4为什么有必要删除与第二波的连接4次呢?因为TCP是一个全双工协议,必须单独拆除每一条信道。注意,4次挥手和3握手的含义不同,很多人会问为什么建立连接是3第二次握手,而删除连接是4次挥手。

3握手的目的很简单,就是分配资源,初始化序列号。此时,尚未涉及数据传输,3这足以做到这一点,并且4第二波的目的是终止数据传输并回收资源。此时,两个端点在两个方向上的序列号不再有任何关系,需要等待两个方向没有数据传输后再拆除虚拟链路。与初始化不同,它不像发现那么简单SYN初始化序列号并确认SYN的序列号。因此,必须单独终止一个方向的数据传输。
疑难杂症2:TIME_WAIT状态

为什么这种状态是必要的, 原因很简单,那就是每次建立连接的时候序列号都是随机产生的,并且这个序列号是32是的,它会环绕。 现在让我解释一下,TIME_WAIT怎么了。

任何的TCP细分应该尽其所能IP网络上传输,中间的路由器可能会随意的缓存任何的IP数据报,它不关心这个IP数据报上被承载的是什么数据,然而根据经验和互联网的大小,一个IP数据报最大生存期MSL(这是基于地球的表面积,电磁波在各种介质中的传输速率,以及IP协议的TTL等综合推算出来的,如果在火星上,这个MSL它会大得多)。

现在我们正在考虑在被动方发送FIN然后活跃的一方回复了ACK然而,这ACK可能会丢失,这会造成被动方重发FIN,这个FIN可能在互联网上生存MSL。

如果没有TIME_WAIT假设连接1它已被断开连接,但上次由其被动端重新传输的那个FIN(或者FIN任何以前发送的TCP分段)还在网络上,然而连接2重复使用的连接1的所有的5元素(源IP,目的IP,TCP、源端口、目标端口)正要建立连接,连接1迟到的FIN到达了,这个FIN将以相对较低但确实可能的概率终止连接2.

为什么概率比较低?这涉及匹配问题,延迟FIN分段序列号必须位于连接上2在一方的预期序列号范围内。虽然这种巧合很少发生,但它确实会发生,因为初始序列号是随机生成的。因此,终止连接的主动方必须接受被动方并回复ACK之后等待2*MSL进入时间CLOSE状态,乘以2因为这是一种保守的算法,在最坏的情况下,对于被动方ACK在以最长路线(经历一个MSL)通过互联网到达被动方后立即丢失。

为了应对这个问题,RFC793有一个生成初始序列号的建议,即设置一个基准并在此基准之上将其随机化。这个基准是时间,我们知道时间单调增加。但是,这仍然存在一个问题,即包装问题。如果发生换行,新的序列号将降至非常低的值。 因此,最好的方法是避免“重叠”,这意味着设置一个高于基准的随机性范围。

要知道,很多人不喜欢看到大量的TIME_WAIT连接的状态,因此它们将TIME_WAIT设置的值非常低,虽然在大多数情况下可行,但它确实是一种冒险行为。最好的方法是不要重用连接。

疑难杂症3重用连接和重用套接字
这是根本不同的,单独重用套接字通常没有任何问题,因为TCP它基于连接性。例如,在服务器端,一个TIME_WAIT连接,然后连接标识一个五元素,只要客户端不使用相同的源端口,连接服务器就没有问题,因为它是迟到了FIN永远不要达到此连接。请记住,五元素标识连接,而不是套接字(当然,对于BSD在套接字方面,服务器端accept套接字确实标识了连接)。

3.2.2.传动可靠性

基本上,传动可靠性是通过确认号来实现的,这意味着对于发送的每个段,接收端必须发送一个确认,而发送端在收到确认后只能发送下一个字节。这个原则就像教科书的“停止”一样简单-“等待”协议是该原则的字节版本,但是TCP使用滑动窗口机制,以便一次不能发送一个字节,但这是以后的事情。本节将仅讨论确认的超时机制。

你怎么知道数据是否到达另一端?那就是从另一端发送确认,但如果无法收到来自另一端的确认,发送端会等待多久?如果您继续等待,您将无法检测到数据丢失,并且协议将不可用。如果等待时间太短,可能会确认仍在途中,因此等待时间是一个问题。此外,如何管理此超时时间也是一个问题。

疑难杂症4超时时间的计算
绝对不建议随意推测超时时间,而是提供准确的算法来计算它。毫无疑问,一个TCP分段回复的到达时间是数据报的往返时间,因此标准定义了一个新术语RTT,表示TCP分段的往返时间。然而我们知道,IP网络正在尽最大努力,路由是动态的,路由器将在没有警告的情况下缓存或丢弃任何数据报。因此,这RTT它需要动态测量,这意味着它应该至少每隔一段时间进行一次测量。如果每次都一样,一切都会好起来的。然而,世界不是你想要的,所以我们需要找到确切的“平均值”而不是准确的值。

如果仅通过直接计算多个测量值来取该平均值作为算术平均值,则不合适,因为对于数据传输延迟,我们必须考虑路径延迟的瞬时抖动,否则如果两个测量值2和98所以超时值将是50此值适用于2例如,它太大,导致数据延迟过大(重新传输应该重新传输的内容需要很长时间)但是,对于98在尺寸方面,它太小,导致过度重传(旅程很长,应该很慢,但大量转播被正确确认但被延迟了TCP分段)。

因此, 除了考虑每两个测量值的偏差外,还应考虑变化率。如果变化率太大,应主要通过以变化率为自变量的函数来计算RTT(如果它突然增加,则需要更大的正数;如果它突然减少,它取一个较小的负数,然后加权并与平均值求和)相反,如果变化率非常小,则将取测量的平均值。 不用说,这种算法至今仍然运行良好。

疑难杂症5超时计时器的管理-每连接单一计时器
显然,对于每一个TCP最直接的方法就是为每个段生成一个定时器,作为每个定时器RTT过期时间,如果没有收到确认,将重新传输。但是,这只是理论上合理的,因为对于大多数操作系统来说,它会产生大量的内存和调度成本,因此每个TCP连接单个定时器的设计已成为默认选择。但是,单个计时器如何管理如此多的传出消息TCP细分呢?如何设计单个计时器。

设计单个计时器有两个原则:1.每一条长时间无法确认的消息,都必须能够超时;2.这是无法长期衡量的,也无法在中长期内接受的。RTT相距太远。因此RFC2988定义一组非常简单的原则:

a.发送TCP分段时,如果重传定时器尚未打开,则将其打开。
b.发送TCP分段时,如果已经激活了重传定时器,则不再激活。
c.收到非冗余消息ACK如果有数据在传输,请重新启动重传计时器。
d.收到非冗余消息ACK如果传输中没有数据,请关闭重传计时器。

我们来看看这个4规则如何实现以上两点a和c(在c在,请注意ACK它是非冗余的),任何TCP只要分段未确认,超时计时器将始终过期。但是,为什么有必要c怎么样?只有规则a如果存在,也可以实现原则1。其实确实如此,但为了避免过早重传,增加了规则c如果没有规则c所以,万一重传定时器到期之前发送了一些数据,这样定时器到期后,除了提前发送的数据外,还可以接收ACK稍后发送的其他数据ACK他们都不会来,所以这些数据将被重新传输。有规则c之后,只要有段ACK到了的时候,重置重传定时器,这是非常合理的,所以在大多数正常情况下,从数据的发布到ACK这个时期的到来和计算RTT重传定时器超时与重传定时器超时差异不显著ACK在到达时重置计时器可以防止传入数据过早重新传输。

这里还有一些细节需要解释。一ACK我们在这里,表明以下内容ACK它很可能按顺序到达,这意味着损失的可能性不高。此外,即使确实有后来者TCP分段损失最多发生2在计时器的超时范围内重复(假设消息是在第一条消息的开始计时器之后立即发送的,则丢失ACK到达后,计时器重新启动,并在重新传输之前经过超时时间)。虽然这里还没有涉及拥塞控制,但可以看出,网络拥塞会导致丢包,从而导致重传。过度的重传反过来会加剧网络拥塞并制定规则c结果可以减轻过多的重传,毕竟启动定时器后发送的数据重传超时最多可以增加两倍。根据原理实现了约两倍的最大超时偏差2,即“这是无法长期衡量的,也无法在中长期内接受的。RTT相距太远。

还有一点,如果是一个发送序列的最后一个分段丢失了,后面就不会收到冗余ACK这样,我们只能等到超时,超时时间几乎肯定会比计时器超时时间长。如果此段在发送序列中较晚的时间发送,并且与之前的发送时间相距较远,则其超时时间不会很大,否则会比较大。

疑难杂症6:何时测量RTT
目前很多TCP实现时间戳,这更方便。发送端不再需要保存发送段的时间,只需将其放在协议标头的时间戳字段中,然后接收端将其回显到ACK好的,然后发件人收到它ACK之后,取出时间戳并与当前时间进行算术差以完成一次RTT的测量。

3.2.3.数据序列

基本上,传动可靠性是通过序列号实现的。

疑难杂症7:确认号和超时重新传输
确认号码是一件非常奇怪的事情,因为TCP对于发送方发出的数据序列,只要收到确认号,就认为确认号之前的所有数据都已收到。即使丢失了之前的确认号码,也就是说,发件人也只能识别最后一个确认号码。这是合理的,因为确认号是由接收端发送的,接收端只确认按顺序到达的最后一个TCP分段。

此外,发件人重新发送TCP收到的消息TCP分段的确认号并不表示已收到重新传输的消息,或者可能是由于已经收到数据ACK丢失或其ACK延迟到达导致超时。值得注意的是,接收端会丢弃任何重复的数据,即使重复的数据被丢弃ACK我仍然会毫无错误地发送它。

标准的早期阶段TCP实现为,只要一个TCP分割损失,即使随后TCP所有网段都已完全接收,但发送方仍会从丢失的网段开始重传所有消息,这可能会导致重传风暴的问题,即一段丢失,从而导致大量重传。这种风暴其实是不必要的,因为大多数TCP在实现中,接收端已经缓存了乱序段,这些已经重传和丢失的段极有可能在到达接收端时被丢弃。这一点在引入拥塞控制后会提到(问题首先说明为快速:丢包导致的超时表明网络可能已经拥塞,重传风暴只会加剧其拥塞程度)。

疑难杂症8重新排序的数据缓存和选择确认
TCP是保证数据顺序的,但是并不意味着它总是会丢弃乱序的TCP分割,是否会被丢弃,都与具体的实现有关,RFC如果内存允许,建议缓存这些无序段,然后实现一种机制,当缓存段可以连接成有序序列时,将它们连接起来,类似于IP协议中的分片是相同的,但由于IP数据报是不确认的,因此IP协议的实现必须缓存任何收到的分片,并且不能丢弃它们,因为IP分区,它永远不会再来了。

现在,TCP实现了一个名为 选择确认 接收端将明确告诉发送端哪些段需要重新传输,而不是哪些段。这无疑避免了重传风暴。

疑难杂症9:TCP倒带序列号的问题
TCP的序列号回绕会引起很多的问题,比如序列号为s细分发布后,m几秒钟后,序列号大于s小序列号是j分段已发布,但此时j比上一个s如果还有一个循环,这就是倒带问题。如果后一段到达接收端,则会造成完全混乱-本来j该在s后来,结果居然到了前面,这种紊乱是TCP无法检查协议。让我们仔细想想,这种情况确实会发生。数据分段不会一次发送一个字节。如果速率为1Gbps的网络,TCP发送端1秒会发送125MB的数据,32可以传输位的序列号空间2的32对于字节的幂,也就是说32换行将在几秒钟左右发生,我们知道这个值远小于MSL值,因此它会发生。

有一个细节可能会引起误解,那就是TCP窗口大小空间是序列号空间的一半,因此它恰好在满载下用数据填充发送和接收窗口,并且序列号空间刚好足够。然而,事实上,TCP的初始序列号不是来自0最初,但随机生成(当然,我们需要协助一些更复杂的算法。)因此,如果初始序列号相对接近2的32的力量,那么它很快就会缠绕起来。

当然,时间戳选项现在可用于帮助识别序列号的一部分。当遇到环绕情况时,接收方需要比较时间戳。我们知道时间戳是单调递增的,虽然它也可以环绕,但环绕时间要长得多。这只是一种策略,这里不详细讨论。还有一个很实际的问题,理论上序列号会绕来绕去,但实际上,有多少TCP端点主机直接安装在1G网线的两端以及接收器和发送器的窗口可以同时填充。此外,即使发生倒带,也不是一件特别的事情。倒带在计算机中太常见了,只需要可识别即可解决问题TCP在序列号方面,在高速网络上(点对点或以太网)数据两端乱序的概率非常低,所以当一个序列号突然变成0或者,如果终止序列号小于起始序列号,则通过将其与先前确认的段进行比较,很容易区分它。如果它位于通过路由器的网络的两端,它将触发IP对数据报重新排序TCP一般来说,虽然仍然会有环回,但速度会慢得多,并且考虑到拥塞窗口(目前未推出)通常不会太大,而且窗口也很难填满65536。

3.2.4.端到端流量控制

使用滑动窗口实现端到端流量控制。推拉窗的原理很简单,基本上是一个生产者/消费者模式

疑难杂症10流量控制的真正含义
很多人认为流量控制可以有效地协调两端的流量匹配,这是事实,但如果考虑网络利用率问题,TCP的流量控制机制并不是那么完善,造成这种情况的原因是滑动窗口只限制了发送的最大数据,而没有限制发送的最小数据,导致一些非常小的数据被封装到TCP分段,消息协议头比例过大,导致网络利用率下降,导致以下内容,这就是端到端的含义TCP协议效率。

承上启下  
终于到了详细说明这个问题的时候了TCP协议实现非常简单,这也是TCP我们很快就会发现该标准实施的各种问题。这些问题引起了标准化协会的关注TCP协议经历了大量的修补,这些补丁的组合让人们感到困惑和茫然。本文件旨在区分这些混乱的情况。事实上,根据RFC这些混乱的局面,都能找到各自的发展轨迹。  

4.端到端TCP协议效率

4.1.三个问题和解决方案

问题1说明:接收端处理缓慢,导致接收窗口被填满
这显然是费率不匹配引起的问题,但即使费率不匹配,只要滑动窗口能够很好地协调它们的速率,无论是快还是慢,滑动窗口在这方面都做得很好。但如果非要从效率的角度来考虑这个问题,现实就不会那么乐观了。考虑到此时接收窗口已经满,慢速应用程序会缓慢读取一个字节,腾出一个位置,然后通知TCP发送端知道有空位,立即发送一个字节,填满接收端,然后接收应用再次变慢......这就是困惑窗口综合症,这是大多数人都熟悉的术语。此问题极大地浪费了网络带宽并降低了网络利用率。就像从大同拉出来100吨煤到北京需要一辆车,拉1Kg我们还需要一辆车来运煤到北京(一个超级夸张的例子,请不要相信)但开车去北京的费用是肯定的

问题1解决方案:窗口通知
对于问题1显然,问题出在接收端。我们不能限制发送端发送小段,但可以限制接收端通知小窗口,这是合理的,不影响应用。在这种情况下,经典延迟/吞吐量的反定律将不再适用,因为接收窗口已满,将其空间的一半留空表示仍有一半的空间未被应用程序读取。将一个字节的空间留空的效果是相同的,因此当窗口0当,直接通知发送端阻止其继续发送数据时,只有当其接收窗口再次到达时MSS当它的大小只有一半时,它只宣布它不是0的窗口,此前对于所有的发送端的窗口probe分段(用于检测接收器窗口的大小probe分段,由TCP标准规定)所有通知窗口都是0,以便发送方不会收到0公告必须是一个相对较大的窗口,因此发件人一次可以发送一个大窗口TCP细分,包括大量数据,意味着数十吨煤炭被拉到北京,而不仅仅是几公斤。

即限制窗口通知的时间,解决窗口混淆综合症的问题
问题2说明:发件人继续发送小数据包,导致窗口空闲
这显然是发送端引起的问题,接收端的窗口是敞开的,但发送方不会积累数据,只是分段发送小块数据。只要发送任何和所有段,接收端必须无条件接收并确认,完全符合TCP标准化,因此有必要限制发送者发送如此小的段。

问题2解决:Nagle算法
Nagel算法非常简单和标准Nagle算法为:

IF 数据的大小和窗口的大小都超过MSS
Then 发送数据分段
ELSE
IF 而那些发出来的TCP细分的确认尚未到来
Then 将数据累积到发送队列的末尾TCP分段
ELSE
发送数据分段
EndIF
EndIF

但后来,这个算法发生了变化,变得更加灵活,包括:
IF 而那些发出来的TCP细分的确认尚未到来
变成了
IF 而那些发出来的不足MSS大小的TCP细分的确认尚未到来

所以如果一个MSS段的大小尚未确认,将来可以随时发送一小部分。此改进减少了算法对延迟的影响。该算法体现了一种自适应策略,其中确认越快,传输越快Nagle算法看起来在积累数据增加吞吐量的同时也加大的时延,可事实上,如果对于类似交互式的应用,时延并不会增加,因为这类应用回复数据也是很快的,比如Telnet像这样的服务不可避免地需要回显字符,因此它们可以自适应地与对等方协调。

注意,Nagle默认情况下,该算法处于启用状态,但可以将其关闭。如果启用,它将严格按照上述算法执行。

问题3.确认号(ACK)它本身是一个没有数据的段,所以大量的确认号码会消耗大量的带宽
这是TCP然而,为了确保可靠的传输标准,在大多数情况下,ACK它仍然可以与数据一起传输。如果没有捎带式传输,则只能单独返回一个ACK如果这样的分段太多,网络的利用率就会下降。乘火车从大同到北京100吨煤,为了确认收到煤,北京需要派一列空车去大同报,因为没有其他交通工具,只有火车。如果线人刚开火车,一车煤从大同运来,运煤车就得开着空火车报案。

问题3的解决:
RFC建议采用延迟方法ACK,也就是说,ACK收到数据后,不会立即回复,而是延迟一段时间。延迟一段时间的目的是看看它是否可以与接收方想要发送给发送方的数据一起返回,因为TCP如果可能,协议标头始终包含确认编号ACK将其重新组合在一起,从而提高网络利用率。向大同报到的确诊人,不需要空车回大同。这时,北京有一批货物需要发往大同。确认人员带着这批货物坐火车回大同。

如果在等待可接受的时间段后仍然没有数据要发送到发送端,此时需要发送单独的数据ACK然而,即便如此,这还是延迟了ACK虽然不是等待可以携带的数据分割,但它也可能在等待未来的到来TCP细分,以便它们可以与最大的一起返回,你知道,TCP的确认号是收到的顺序消息之后的最后一个字节。最后RFC建议,延迟ACK等待最多两个段的累积确认。

4.2.分析三个问题之间的相关性

三个问题引起的结果是相同的,但需要注意的是,它们的原因根本不同1几乎总是在接收端窗口已满时发生,并且问题2几乎总是发生在窗口闲置的情况下,问题3这似乎是最无聊的,但由于TCP的要求,必须要有确认号,而且一个确认号就需要一个TCP不包含数据的细分无疑非常小。

这三个问题都导致网络利用率下降。虽然两个问题导致相同的结果,但有必要认识到它们是不同的问题,并自然地将这些问题的解决方案聚合起来形成一个全局解决方案,这就是当今操作系统中的解决方案。

4.3.问题的杂糅情况

疑难杂症11:混淆的窗口解决方案和Nagle算法
困惑窗口综合征患者希望在发送端积累信息TCP分段,而Nagle该算法确实保证了一定程度的准确性TCP发送端分段的累积,此外,延迟ACK发送端将利用此延迟时间来累积数据。但是,这是三个不同的问题。Nagle算法可以缓解混淆窗口综合症,但它们不能治愈根本原因。

疑难杂症12:Nagle算法和延迟ACK
延迟ACK会延长ACK到达发送端的时间,由于标准Nagle该算法只允许一个未经确认的TCP分段,无疑是在接收端,这种延迟ACK是毫无希望等待后续数据到来最终进行积累确认的,如果没有数据可以捎带这个ACK所以这个ACK仅当延迟确认计时器超时时才会发出它,该计时器正在等待此ACK在此过程中,发送方积累了一些数据,导致延迟ACK实际上,它以增加延迟为代价得到了加强Nagle算法。延迟ACK加Nagle算法的情况下,接收端只有不断有数据要发回,才能同时既保证了发送端的分段积累,又保证了延迟不增加,同时还没有或者很少有空载的ACK。

你知道,延迟ACK和Nagle这是两个问题的解决方案。
疑难杂症13我什么时候可以发送数据
我什么时候可以发送数据?如果只是从Nagle从算法的角度来看,这似乎很简单,但事实证明情况更加复杂。如果发件人已经安排3个TCP分割1,分段2,分段3按顺序排列,所有三个细分市场都是小细分市场(不符合Nagle立即发送算法的标准)此时,已经发送了一个片段,其确认尚未到达。您能否此时发送片段1和2吗?如果按照Nagle算法不能发送,但实际上可以发送,因为这两个段不再有任何积累新数据的机会,新数据肯定会在段中积累3是的。问题是,如何在新段累积到一定大小之前生成它们?这是可能的,但这是另一个问题,这里不会讨论。

Linux的TCP实现在这个问题上表现的更加灵活,它是这么判断能否发送的(在开启了Nagle的情况下):

IF (尚未确认超过拥塞窗口大小的数据分段 || 包含在数据细分中FIN ) &&
数据分段不超过窗口边界
Then
IF 分段在中间(上面示例中的分段1和2) ||
分段是紧急模式            ||
通过以上Nagle算法(改进后的Nagle算法)
Then 发送分段
EndIF
EndIF

我以前也改过Nagle算法,特别是不修改Nagle该算法修改了“什么时候可以发送数据”的策略。过去,发送端用于判断是否可以发送数据,但如果此时有延迟ACK等待携带,由于积累不足或其他原因无法发送要发送的数据,所以双方都在等待,这在某些情况下实际上不是很好。在我所做的改进中,添加了另一种关于何时可以发送数据的情况,即”ACK在“拉”的情况下,一旦有延迟ACK等待发送,检查是否有任何数据等待发送,如果有,请检查数据是否足够大。在这里,我选择MSS的一半:

IF (尚未确认超过拥塞窗口大小的数据分段 || 包含在数据细分中FIN ) &&
数据分段不超过窗口边界
Then
IF 分段在中间(上面示例中的分段1和2) ||
分段是紧急模式            ||
通过以上Nagle算法(改进后的Nagle算法)
Then 发送分段
EndIF
ELSE IF 有延迟ACK等待传输                &&
在发送队列中等待发送TCP分段       &&
发送队列的标头段大小大于MSS的一半
Then 延迟发送队列标头分段ACK
EndIF

此外,发送队列标头段的大小可以在统计意义上动态计算,并且不一定非要MSS尺寸的一半。我们发现该算法对交互式网络应用具有自适应性。键入速度越快,特定时间内累积的段越长,对等方响应速度越快(可以捎带ACK)本地端发送速度越快(以Echo举例说明以便更好地理解)。

疑难杂症14:《TCP/IP详解(卷一)》中Nagle算法示例的解释
我在网上搜索了很多这个问题的答案,有人说RFC有些人建议别的东西。但实际上,这是一个典型的“种族问题”:

首先,服务器发送了两个段:
数据段12:ack 14
数据段13:ack 14,54:56
然后客户端发送了两个段:
数据段14:ack 54,14:17
数据段15:ack 56,17:18

您可以查看数据细分受众群14应该已经确认56是的,但确认的是54。也就是说,当数据段已经移出队列,即将发送但尚未发送时,数据段13刚到,软中断处理程序抢占了数据段14发送过程应注意,此时仅发送数据段14移出队列而不更新任何状态信息,例如“发出但未确认的段数”,此时软中断处理程序成功接收段13,然后更新窗口信息,并且检查看有没有数据要发送,由于分段14它已被移出队列,下一个接受发送检查的是分段15是的,由于状态信息尚未更新,因此已分段15已成功通过发送检测,发送完成。

可以看Linux了解源代码,tcp_write_xmit这个函数会在两个地方调用,一个是TCP在发送过程中,另一种是软中断的接收和处理,两者在通话中的竞争可能会导致“说明”中描述的情况。请注意,这种解锁传输方法是合理且最有效的,因此TCP处理语义将做出判断并丢弃所有不应该接收或重复接收的段。

承上启下  
是时候连接前面和后面了,这就是我们需要说的TCP一切都很简单TCP即使很简单TCP上面提到的问题也很多,更别说继续增加TCP复杂性增加了。到目前为止,我们的TCP都是端到端,然而实际上TCP要跑在IP在线,而IP网络有很多问题,这是一个非常拥挤的网络。不幸TCP一些与确认和可靠性相关的机制也会恶化IP网络拥塞。  

5.IP在线TCP

5.1.端到端的TCP协议和IP协议之间的冲突

端到端的TCP只能看到两个节点,那就是自己和对方,它们是看不到任何中间的路径的。 可是IP互联网是一跳一跳的,它们的矛盾在于TCP端到端流量控制必然导致网络拥塞。因为每个TCP连接的一端只知道另一端有多少空间来接收数据,他们不在乎到另一端的路径上是否有这么大的容量。事实上,所有连接的这些空间的总和将立即超过IP因此,网络的容量TCP根据滑动窗口流量控制机制也不可能完美运行。

不可避免地需要一种拥堵控制机制来反映路径的拥堵情况。
疑难杂症15拥塞控制的本质
由于TCP它是一个端到端的协议,所以两端之间的控制类别属于流量控制,IP网络的拥塞会导致TCP分段的丢失,由于TCP中间路由器看不见,所以这种损耗只发生在中间路由器,当然是两个端点的网卡或者IP即使图层丢失数据分割TCP无形。因此,拥塞控制不可避免地作用于IP链接。事实上,我们可以知道拥塞控制仅在以下情况下有效:

a.两个或多个连接(其中之一必须是TCP另一个可以是任何连接)通过同一路由器或链路时;
b.只有一个TCP但是,当它通过路由器时连接。

在其他情况下,不会有拥堵。因为TCP始终希望对整个网络路径具有独占访问权限,这对于多个连接是不可能的,必须确保TCP这种拥塞控制机制的公平性是合理的。本质上,拥塞的原因是每个人都想垄断所有带宽资源,导致拥塞,这毕竟也是合理的TCP无法查看网络状态,这也决定了TCP拥塞控制必须采取探索性的方法,最终达到足以触发其“响应”的“刺激点”。

拥塞控制需要完成以下两个任务:1.公平性;2.拥堵后退出拥堵状态。

疑难杂症16影响拥堵的因素
我们必须认识到,拥堵控制是一种整体机制,不倾向于任何TCP连接,因此这种机制本质上包括公平性。那么影响拥堵的因素有哪些呢?具有讽刺意味的是,起初TCP没有拥塞控制机制,正是TCP加班重传风暴(段丢失会导致已发送的后续段被重新传输,并且这些重新传输中的大多数是不必要的)网络拥塞增加。因此,重传一定不能过频,重传定时器的超时时间必须设置得稍长一些,这在单个重传定时器的设计中得到了加强。此外TCP除了自身因素外,所有其他拥塞都可以通过拥塞控制机制自动完成。

另外,不要将路由器视为线路速度转发设备。任何连接到网络的好路由器都会降低网络的总带宽,因此即使只有一个TCP连接由于TCP发送方始终使用发送链路的带宽发送分段,并且当这些分段通过路由器时,排队和处理这些分段时总是存在延迟,因此最终丢包是不可避免的。

最后,丢包的延迟也会加剧拥塞。假设TCP连接传递N路由器,正面N-1所有路由器都可以顺利转发TCP分段,但最后一个路由器丢失了一个分段,这导致这些丢失的分段浪费了前一个路由器的大量带宽。

5.2.拥塞控制策略

在介绍拥塞控制之前,首先介绍一下拥塞窗口,它实际上表示的也是“可以发送多少数据”然而,这和接收端通告的接收窗口意义是不一样的,后者是流量控制用的窗口,而前者是拥塞控制用的窗口,体现了网络拥塞程度。

拥塞控制一般分为两类:探索性拥塞检测和拥塞避免(注意,不是常规意义上的拥塞避免)。

5.2.1.探索性拥塞检测可分为两类:拥塞窗口的慢启动和加性扩展(这也称为拥塞避免,但此方法无法避免拥塞)。

5.2.2.拥塞避免方法:拥塞控制旨在在拥塞发生之前提醒发送方,使网络拥塞,使发送方可以进入快速重传模式/快速恢复或显式减少拥塞窗口,以避免网络拥塞,这可能导致超时和启动缓慢阶段。

5.2.3.快速重传和快速恢复。所谓快速重传/快速恢复针对慢启动,我们知道慢启动应该从1个MSS开始增加拥塞窗口并快速重新传输/收到后快速恢复3个冗余ACK与其进入慢启动,不如将拥塞窗口减少到当前阈值的一半加上3然后,如果您继续获得冗余ACK,则将拥塞窗口加1个MSS直到收到新数据ACK将窗口设置为正常阈值,然后开始加法增加阶段。

为什么在进入快速重传时,拥塞窗口要减少到当前阈值的一半3呢?加上3基于数据包保存,因为我们收到了它3个冗余ACK它表示三个数据段已经到达接收端。由于三个段已经离开网络,这意味着它们可以发送3它是分段的,只要我们收到另一个冗余ACK这也表明1分段已离开网络,因此将添加拥塞窗口1个MSS。直到收到一个新的ACK解释直到收到第三个冗余ACK期间发送TCP这些段已经到达了另一端,此时,正常阶段开始添加拥塞窗口。

疑难杂症17:超时的重新传输和接收3个冗余ACK后重传
这两种重传的含义不同,超时重传一般是由于严重的网络拥塞(没有一个部分到达,如果有,肯定会有ACK的,若是正常ACK重置重新传输计时器(如果冗余)ACK,可能是由于单个消息丢失或重新排序,如果连续3个冗余ACK,则很可能丢失单个段)此时,有必要更严厉地缩小拥塞窗口,从而进入缓慢启动阶段。并收到3个冗余ACK以下语句表明确实存在中间段丢失,但后续段确实到达了接收端,这就是发送冗余的原因ACK这通常是由路由器故障、轻度拥塞或其他不太严重的原因引起的,所以此时拥塞窗口不宜减少太多,启动快速重传/快速恢复阶段。

疑难杂症18:为何收到3个冗余ACK后才重传
这是一个权衡结构,接收两个或一个冗余ACK也可以重新传输,但这可能会导致不必要的重新传输,因为两个数据段无序的可能性不高,并且三个以上的数据段无序的可能性很高。换句话说,如果只接收到一个乱序网段,则很可能被中间路由器重新排列,而另一个网段很可能立即到达。但是,如果连续收到3没有一个片段能够弥补这一差距,很可能它已经丢失,需要重新传输。 因此3个冗余ACK这是减少不必要的重传和确实检测单个段丢失之间的权衡。
注意,冗余ACK它不能携带。

疑难杂症19乘法约简和加法增加的深层含义
为什么是乘法递减和加法递增?拥堵窗口的增加只对自己有利,而拥堵窗口的减少对每个人都有好处,但自己却受到伤害。哪个更重要?我们知道TCP公平性嵌入在拥塞控制中,正是这种乘法式减少实现了公平。拥挤的窗户1个MSS此更改会影响TCP发件人,为了减少他们的拥塞窗口并产生更大的影响TCP发送者-为了使更多的发送者受益,采用了乘法减少策略。

当然,BIC该算法提高了加法增长的效率,不再一一MSS一次添加更多而不是添加更多MSS,采取 二分查找 逐渐找到不会导致丢包的点,然后添加其他功能。

疑难杂症20:TCP连接的稳定传输状态是什么
首先,我们来谈谈如何确定发送方的发送窗口,它取拥塞窗口的最小值和接收方的通知窗口。然后,我们为发送窗口提出了三种稳定状态:
a.IP经典的锯齿形,在互联网接收端带有大窗户
b.IP互联网接收端具有小窗口的线性状态
c.直连网络端点之间满载下的直线状态

其中a它是大多数州,因为一般来说,TCP连接都是在互联网上建立的,并且很多,例如Web浏览,电子邮件,在线游戏,Ftp下载等等。TCP发送端使用慢启动或拥塞避免方法不断增加其拥塞窗口,直到发生丢包,然后进入慢启动或拥塞避免阶段(这取决于丢包是由于超时还是冗余ACK丢包)此时,发送窗口将下降到1或者,它可以减少一半。在这种情况下,接收端的接收窗口一般都比较大,毕竟IP网络并不是什么很快速的网络,一般的机器处理速度都很快。

但是如果接收端特别破碎,处理速度慢,会导致它通知一个非常小的窗口。这样,即使拥塞窗口很大,发送端仍将使用通知的接收窗口作为发送窗口,这样就不会发生拥塞。最后,如果唯一TCP如果连接在两个直接连接的主机上运行,它将独占地享受网络带宽,因此TCP数据流将在最佳情况下填充网络管道(我们将网络管道定义为带宽和延迟的乘积)其实这种情况是没有拥堵的,就像在雨天黄昏独自徘徊在街上一样。

5.2.4.主动避免拥塞

我们前面介绍的拥塞控制方法都是探索性检测,然后拥塞窗口被动地进行乘法缩减,这样当接收窗口很大的时候(一般都是这样,网络拥堵,分段就不会轻易到达接收端,导致接收端的窗口大量空置)“时间”可能呈锯齿状-橱窗“形象,类似拥挤的北京X在环上行驶,启动发动机,启动汽车,停止,等待,启动发动机,启动汽车...您还可以听到声音。

虽然TCP看不到下面IP但是,仍然可以检测到网络RTT计算拥塞窗口中的变化和拥塞窗口中的变化IP网络的拥堵情况的。就比方说北京东四环一家快递公司要持续送快递到西四环,当发件人发现货到时间越来越慢的时候,他会意识到“下班高峰期快到了”…

可以通过连续观察来实现RTT主动调整拥堵窗口的大小,而不是盲目增加拥堵窗口。但是,还有一种更强大的算法,即计算两个差值的乘积:
(当前拥塞窗口-上一次拥塞窗口)x(当前的RTT-上一次的RTT)

如果结果为正数,则拥塞窗口减小1/8,若结果是负数或者0,然后将一个添加到窗口MSS。请注意,这次不再是乘法约简。可以看出,归约的幅度小于乘法约简的量级,因为这种拥塞控制是主动的,而不是之前使用的被动探测方法。在探索性方法中,乘法减少以惩罚的方式实现公平,而在主动方法中,当实现拥塞时,TCP发送方主动减小拥塞窗口,为了鼓励这种投降行为,采用了小幅减少拥塞窗口。需要注意的是,在减少拥堵窗口的过程中,产品之前的差值是负数。如果后一个差值也是负数,则结果是继续减小窗口,直到拥塞缓解或窗口减少到一定程度,使后一个差值成为正数或0在这种情况下,后一种差异只能变成0。

疑难杂症21:路由器和TCP的互动
虽然有了5.2.4路由器是否可以执行任何操作来帮助检测拥塞,如活动拥塞检测部分所述?路由器的这种扩展是必要的,因为有无数TCP通过路由器,尽管路由器不在乎TCP协议中的任何内容(当然排除连接跟踪之类的,这里所说的是标准的IP路由器),但是它却能以一种很简单的方式告诉TCP的两端IP网络正在经历拥塞, 这种方法是在路由器检测到轻微拥塞时随机丢弃数据包,随机数据包丢失而不是连续数据包丢失对于TCP由于随机丢包可能导致,因此具有重要意义TCP发现单个段已被丢弃,后续段仍将到达接收端,因此TCP发送端就会接收到3个冗余ACK,然后进入快速重传/快速恢复而不是缓慢启动。

这就是路由器可以提供帮助的方式TCP做的事。

6.其它

疑难杂症22如何学习TCP
许多人发布问题TCP相关内容,接下来要有意思的就是展示一下《TCP/IP详细解释和《Unix我认为这种回答对于网络编程中的特定章节是非常不负责任的。因为我觉得这两本书不是很有帮助,确实写得很好,但是可以看出,Richard Stevens他是一个实用主义者。他喜欢用例子解释一切tcpdump此方法仅适用于已经TCP然而,理解得很好的人,大多数人都无法理解。

从设计的角度来看,这两本书都很糟糕。我认为我们应该从一些初学者开始,例如Wiki类似的东西,然后看看它RFC文档,793,896,1122等)所以你可以理解TCP为什么它被设计成这样,而你永远做不到Richard Stevens从书中获得。最后,如果你愿意,那就看看吧Richard Stevens一本书最重要的事情是编写一些代码或键入命令,然后抓取包并自己分析。

疑难杂症23:Linux,Windows和网络编程
我觉得在Linux上写点TCP代码非常好,如果有的话BSD那就更好了。不推荐Winsock学习TCP。虽然微软声称有API这一切都是为了让事情变得更简单,但实际上,事情变得更加复杂。如果您使用Winsock学习需要你花很多时间掌握与网络编程无关的东西,但是windows平台上却少不了的东西

6.1.总结

TCP协议是端到端的协议,虽然是具有流量控制和拥塞控制的协议,但正是因为这些所谓的控制,TCP变得复杂。同时,这些特性相互交织,流量控制带来了许多问题。这些问题的解决最终会带来新的问题。在解决这些问题时,只考虑端到端的意义,但实际上TCP我们需要尽力而为。IP所提供的网络,因此拥塞成为终极问题,拥塞控制算法的改进也成为一个单独的领域。

在学习TCP在解决这些问题的过程中,我们应该避免下棋。我们必须区分每个算法解决的问题,每个问题与其他问题之间的关系是什么,这些问题的解决方案之间的关系是什么,以及TCP最好对以下方面的发展历史有更好的了解,TCP该协议完全在您的控制之下。接下来,你可以学习Socket API然后高效TCP程序来自您!

版权声明

所有资源都来源于爬虫采集,如有侵权请联系我们,我们将立即删除

热门