TCP/IP详解卷一之传输控制协议(TCP)

1 TCP协议特点
—TCP提供了一种面向连接的、可靠的字节流服务。
—“面向连接的”是指使用TCP的两个应用程序必须在它们可交换数据之前,通过相互联系来建立一个TCP连接。
—“字节流”的结果是没有由TCP自动插入的记录标志或消息边界。
—“可靠性”:
· TCP维持了一个强制的校验和,该校验和涉及它的头部、任何相关应用程序数据和IP头部的所有字段。
· 当TCP发送一组报文段时,它通常设置一个重传计时器,等待对方的确认接收。
· 当TCP接收到连接的另一端的数据时,它会发送一个确认。TCP使用的ACK是累积的。
· TCP给应用程序提供一种双工服务。数据可向两个方向流动,两个方向相互独立。
· 使用序列号,一个TCP接收端可丢弃重复的报文段和记录以杂乱次序到达的报文段。
—TCP把一个发送应用程序的字节流转换成一组IP可以携带的分组,这些分组包含序列号,该序列号在TCP中实际代表了每个分组的第一个字节在整个数据流中的字节偏移,而不是分组号。
—应用程序数据被打散成TCP认为的最佳大小的块来发送,一般使得每个报文段按照不会被分片的单个IP层数据报的大小来划分;而对于UDP来说,应用程序每次写入通常就产生一个UDP数据,其大小就是写入的那么大(加上头部)。

2 TCP头部
在这里插入图片描述
—源端口号、目的端口号:16位,与IP头部中的源和目的地址一起唯一地标识了每个连接。一个IP地址和一个端口的组合有时被称为一个端点或套接字。
—序列号字段:32位,无符号数,标识了TCP发送端到TCP接收端的数据流的一个字节,该字节代表着包含该序列号的报文段的数据中的第一个字节。
—确认号字段(ACK号):32位,包含的值是该确认号的发送方期待接收的下一个序列号,也即最后被成功接收的数据字节的序列号加1。该字段只有在ACK位字段被启用的情况下才有效。
—头部长度字段:4位,以32位字为单位,给出了头部的长度。由于只有4位,TCP头部被限制为最大只能有60字节。
—CWR:拥塞窗口减,表示要求发送方降低它的发送速率。
—ECE:ECN回显,表示发送方接收到了一个更早的拥塞通告。
—URG:紧急,表示紧急指针字段有效,很少使用。
—ACK:确认,表示确认号字段有效,在连接建立以后一般都是启用状态。
—PSH:推送,表示接收方应尽快给应用程序传送这个数据,没被可靠的实现或用到。
—RST:重置连接,表示连接取消,经常因为错误。
—SYN:用于初始化一个连接的同步序列号。
—FIN:该报文段的发送方已经结束向对方发送数据。
—窗口大小字段:16位,窗口大小是字节数,从ACK号指定的那个字节开始,用于TCP的流量控制。由于只有16位,限制了窗口大小最大为65535字节,从而限制了TCP的吞吐量性能。
—TCP校验和字段:16位,包含TCP头部、数据以及伪头部,由发送方进行计算和保存,然后由接收方验证。
—紧急指针字段:16位,只有在URG位字段被设置时才有效。“指针”是一个必须要加到报文段的序列号字段上的正偏移,以产生紧急数据的最后一个字节的序列号。TCP的紧急机制是一种让发送方给另一端提供特殊标志数据的方法。
—选项字段:如最大段大小选项(MSS):连接的每个端点一般在它发送的第一个报文段上指定这个选项。MSS指定该选项的发送者在相反方向上希望接收到的报文段的最大值。

3 SYN报文段
—当建立一个新连接时,从客户机发送至服务器的第一个报文段的SYN位字段被启用,这样的报文段称为SYN报文段。
—SYN报文段的序列号字段包含了在本次连接的这个方向上要使用的第一个序列号,后续序列号和返回的ACK号也在这个方向上。
—SYN的序列号字段的值不是0和1,而是一个随机选择的数字,称为初始序列号(ISN)。
—SYN位字段会消耗一个序列号,因此,发送在本次连接的这个方向上的数据的第一个字节的序列号是ISN加1。
—消耗一个序列号意味着使用重传进行可靠传输,因此,SYN、FIN和应用程序字节是被可靠传输的;而不消耗序列号的ACK则不是。

4 TCP连接的建立和终止
在这里插入图片描述
—一个TCP连接是由一对端点或套接字构成,其中通信的每一端都由一对(IP地址,端口号)所唯一标识。
—一个TCP连接通常分为3个阶段:启动、数据传输(连接已建立)、退出(关闭)。
—一个TCP连接建立过程,也即3次握手过程:
· 主动开启者(客户端)发送一个SYN报文段,并指明自己想要连接的端口号和它的客户端初始序列号(ISN©)。通常,客户端还会借此发送一个或多个选项。
· 服务器也发送自己的SYN报文段作为响应,并包含了它的初始序列号(ISN(s))。此外,为了确认客户端的SYN,服务器将其包含的客户端初始序列号数值加1后作为返回的ACK号。因此,每发送一个SYN,序列号就会自动加1,这样如果出现丢失的情况,该SYN段就会被重传。
· 为了确认服务器的SYN,客户端将包含的服务器初始序列号的数值加1后作为返回的ACK号。
—三次握手的目的不仅在于让通信双方了解一个连接正在建立,还在于利用数据包的选项来承载特殊的信息,交换初始序列号。
—TCP连接的任何一方都能够发起一个关闭操作,此外,还支持双方同时关闭连接的操作。
—TCP连接关闭过程,也即4次挥手过程:
· 连接的主动关闭者发送一个FIN段指明接收者希望看到的自己当前的序列号(K)。FIN段还包含了一个ACK段用于确认对方最近一次发来的数据。
· 连接的被动关闭者将K的数值加1作为响应的ACK值,以表明它已成功接收到主动关闭者发送的FIN。此时,上层的应用程序会被告知连接的另一端已经提出了关闭的请求,通常,这会导致应用程序发起自己的关闭操作。
· 接着,被动关闭者将身份转变为主动关闭者,并发送自己的FIN,并指明对方希望看到的自己当前的序列号(L)。该FIN段还包含了一个ACK段用于对对方发来的FIN进行再次确认。
· 为了完成连接的关闭,最后发送的报文段还包含一个ACK用于确认上一个FIN。
—TCP连接关闭过程中如果出现FIN丢失的情况,那么发送方将重新传输直到接收到一个ACK确认为止。
—TCP半关闭:是指仅关闭数据流的一个传输方向,而另一个方向仍然能继续传输数据。

5 初始序列号
—在发送用于建立连接的SYN之前,通信双方都会选择一个初始序列号。
—初始序列号会随时间而改变,因此每一个连接都拥有不同的初始序列号。
—为一个连接的报文段安排序列号时,应防止出现与其他连接的序列号出现重叠的情况;而且,对于同一连接的两个不同实例,新的序列号也不能出现重叠的情况。
—TCP的脆弱性:如果选择合适的序列号、IP地址和端口号,那么任何人都能伪造出一个TCP报文段,从而打断TCP的正常连接。应对上述行为的方法有:
· 使初始序列号变得相对难以被猜出;
· 加密。

6 TCP选项
—常见选项如下表所示:
在这里插入图片描述
—每一个选项的头一个字节为“种类”,指明了该选项的类型。种类值为0或1的选项仅占用1个字节,其他的选项会根据种类来确定自身的的字节数长度。
—NOP选项:用于填充,允许发送者在必要的时候用多个4字节组填充某个字段。
—EOL选项:指出了选项列表的结尾。
—MSS(最大段大小)选项:是指TCP协议所允许的从对方接收到的最大报文段,也是通信对方在发送数据时能够使用的最大报文段。最大段大小只记录TCP数据的字节数而不包括其他相关的TCP与IP头部。
—窗口缩放选项:能有效地将TCP窗口广告字段的范围从16位增加至30位。该选项只能出现于一个SYN报文段中,当连接建立以后,比例因子是与方向绑定的。窗口的移动数值通常是由TCP通信方根据接收缓存的大小自动选取的。
—选择确认选项:通过接收到SYN报文段中的SACK-Permitted选项,TCP通信方会了解到自身具有了发布SACK信息的能力。当接收到乱序的数据时,它就能提供一个SACK选项来描述这些乱序的数据,从而帮助对方有效地进行重传。
—时间戳选项:要求发送方在每一个报文段中添加2个4字节的时间戳数值。时间戳是一个单调增加的数值,接收方并不关心时间戳数值到底是什么。该选项并不要求在两台主机之间进行任何形式的时钟同步。时间戳主要用于:
· 估算TCP连接的往返时间,从而更好地设置重传超时。
· 作为防回绕序列号,为接收者提供了避免接收旧报文段与判断报文段正确性的方法。防回绕序列号算法并不要求在发送者和接收者之间有任何形式的时钟同步,接收者所需要的是保证时间戳数值单调增长,并且每一个窗口的数据至少增加1。
—用户超时选项:指明了TCP发送者在确认对方未能成功接收数据之前愿意等待该数据ACK确认的时间。建立连接的SYN报文段、首个非SYN报文段以及USER_TIMEOUT的数值发生任何改变的报文段,都会包含用户超时选项。用户超时选项的意义:
· 允许TCP通信方将自己的USER_TIMEOUT数值告知连接的对方,从而方便了TCP接收方调整自己的行为。
· NAT设备也能够解释这些信息以帮助设置它们的连接活动计时器。
—认证选项:用于增强连接的安全性。它使用了一种加密散列算法以及TCP连接双方共同维护的一个秘密值来认证每一个报文段。然而,TCP认证选项没有提供一个全面密钥管理方案。

7 TCP状态转换
—TCP状态转换图如下图:
在这里插入图片描述
—注:从SYN_RCVD返回到LISTEN的状态转换只有在SYN_RCVD状态是由LISTEN状态而非SYN_SENT状态转换而来的情况下才是正确的。
—正常TCP连接的建立和终止过程时客户端与服务器经历的各种状态如下图所示:
在这里插入图片描述
(1)TIME_WAIT状态
—也称为2MSL等待状态,在该状态中,TCP将会等待两倍于最大段生存期(MSL)的时间。
—最大段生存期(MSL):代表任何报文段在被丢弃前在网络中被允许存在的最长时间。
—由于TCP报文段是以IP数据报的形式传输的,而IP数据报拥有TTL字段和跳数限制字段,因此,MSL数值是有限制的。
—当TCP执行一个主动关闭并发送最终的ACK时,连接必须处于TIME_WAIT状态并持续两倍于最大生存期的时间,从而能够让TCP重新发送最终的ACK以避免出现丢失的情况。重新发送最终ACK是因为通信另一方重传了它的FIN,而不是因为TCP重传了ACK(ACK不消耗序列号,不会被重传)。
—当TCP处于等待状态时,通信双方将该连接(客户端IP地址、客户端端口号、服务器IP地址、服务器端口号)定义为不可重新使用。从而可以防止新的连接将前一个连接的延迟报文段解释成自身数据的状况。该连接可被再次使用的三种情况:
· 当2MSL等待结束时。
· 当一条新连接使用的初始序列号超过了连接之前的实例所使用最高序列号时。
· 当允许使用时间戳选项来区分之前连接实例的报文段以避免混淆时。
—对于交互式应用程序而言,客户端通常执行主动关闭操作并进入TIME_WAIT状态,服务器通常执行被动关闭操作并且不会进入TIME_WAIT状态。这表示:
· 如果我们终止一个客户端后立刻重启同一客户端,那么新的客户端也不能重新使用相同的本地端口号。但由于客户端通常使用的是由操作系统分配的临时端口号,而且它们也不关心被分配的端口号究竟是什么,因此这不成问题。
· 而对服务器而言,它们通常使用一些知名的端口。如果我们终止一个已经建立了一条连接的服务器进程,然后立即尝试重新启动它,服务器不能为该程序的通信端分配对应的端口号。
(2)FIN_WAIT_2状态
—在该状态,某TCP通信端已发送一个FIN并已得到另一端的确认。除非出现半关闭的情况,否则该TCP端将会等待另一端发送FIN,该连接才会从FIN_WAIT_2状态转换为TIME_WAIT状态。
—防止连接永远处于FIN_WAIT_2这一无限等待状态的方法:如果负责主动关闭的应用程序执行的是一个完全关闭操作,那就会设置一个计时器,如果计时器超时时该连接是空闲的,那么TCP连接就会转换为CLOSED状态。

8 重置报文段
—重置报文段:将TCP头部的RST位字段置位的报文段。
—一般来说,当发现一个到达的报文段对于相关连接而言是不正确的时,TCP就会发送一个重置报文段。
—重置报文段不会令通信另一端做出任何响应,因此,它不会被确认。
—重置报文段的用途有:
(1)针对不存在端口的连接请求
—对于UDP协议而言,会生成一个ICMP端口不可达消息;而TCP协议会使用重置报文段。
(2)终止一条连接
—有序释放:由通信一方发送一个FIN来关闭一条连接。FIN是在之前所有排队数据都已发送后才被发送出去,通常不会丢失数据。
—终止释放:通过发送一个重置报文段替代FIN来终止一条连接。
—终止释放为应用程序提供两大特性:
· 一个重置报文段会被立即发送出去,任何排队的数据都将被抛弃;
· 重置报文段的接收方会说明通信另一端采用了终止的方式而不是一次正常关闭。
(3)半开连接
—如果在未告知另一端的情况下通信的一端关闭或者终止连接,那么就认为该连接处于半开状态。
—产生半开连接的原因:
· 通信一方的主机发生崩溃;
· 通信一方的主机的电源被切断而不是被正常关机。
—当对处于半开连接的关闭连接的一方传输数据时,接收者会回复一个重置报文段作为响应。
(4)时间等待错误
—如果处于TIME_WAIT状态的TCP通信方接收到来自于这条连接的一些报文段,或是更加特殊的重置报文段,它将会被破坏,从而过早地转移至CLOSED状态,这种情况被称为时间等待错误。
—时间等待错误示例如下:
在这里插入图片描述

9 TCP超时与重传
(1)设置重传超时
—设置重传超时(RTO)的步骤:
· TCP首先需要根据一段时间内的RTT样本值建立好的估计值;
· 然后基于估计值设置RTO。
1)经典方法
—指数加权移动平均(也称为低通滤波器)方法:通过如下公式计算得到平滑的RTT估计值(SRTT):
在这里插入图片描述
—其中常量a为平滑因子,推荐值为0.8-0.9。
—然后通过如下公式设置RTO:
在这里插入图片描述
—其中B为时延离散因子,推荐值为1.3-2.0。ubound为RTO的上边界、lbound为RTO的下边界。
—该方法适用于相对稳定的RTT分布,但对于TCP运行于RTT变化较大的网络中,则无法获得期望的效果。
2)标准方法
—经典方法无法适应RTT的大规模变动。特别是,当实际的RTT远大于估计值时,会导致不必要的重传,而增大的RTT样本值表明网络已经出现过载,此时不必要的重传会进一步加重网络负担。
—改进:通过记录RTT测量值的变化情况以及均值来得到较为准确的估计值。
—公式如下:
在这里插入图片描述
—重传二义性:假设一个包的传输出现超时,该数据包就会被重传,接着收到一个确认信息。那么该确认信息是对第一次还是对第二次传输的确认就存在二义性。
—Karn算法:
· 一、当出现超时重传时,接收到重传数据的确认信息时不能更新RTT估计值,从而可以解决RTT估算中出现的二义性问题。
· 二、TCP在计算RTO过程中采用一个退避系数,每当重传计时器出现超时,退避系数加倍,该过程一直持续至接收到非重传数据,此时,退避系数重新设为1。
—时间戳选项也能用作RTT测量,并且时间戳选项使得发送端即使在丢包、延时、失序的情况下也能测量RTT。
(2)基于计时器的重传
—若在连接设定的RTO内,TCP没有收到被计时报文段的ACK,将会触发超时重传。
—当发生超时重传时,TCP通过降低当前数据发送率来对此进行快速响应。实现方法有:
· 一、基于拥塞控制机制减小发送窗口大小;
· 二、每当一个重传报文段被再次重传时,则增大RTO的退避因子。
—由于RTO的设置通常大于RTT,因此,基于计时器的重传会导致网络利用率的下降。
—当TCP超时重传,它并不需要完全重传相同的报文段,TCP允许执行重新组包,发送一个与原报文段不同大小的报文段。
(3)快速重传
—快速重传机制基于接收端的反馈信息来引发重传。
—与超时重传相比,快速重传能更加及时有效地修复丢包情况。
—当接收到失序报文段时,TCP需要立即生成确认信息(重复ACK),并且失序情况表明在后续数据到达前出现了丢段。
—当失序数据到达时,重复ACK应立即返回,不能延时发送。原因在于使发送端尽早得知有失序报文段,并告诉其空缺在哪。当采用SACK时,重复ACK通常也包含SACK信息,利用该信息可以获知多个空缺。
—网络中出现失序分组的两种可能原因:
· 接收端当前期盼的包可能已经丢失;
· 接收端当前期盼的的包延迟到达。
—快速重复算法可概括为:TCP发送端在观测到一定数目的重复ACK(称为重复ACK阈值或dupthresh)后,重传可能丢失的数据分组,而不必等到重传计时器超时。当然也可以同时发送新的数据。
—不采用SACK时,在接收到有效ACK前至多只能重传一个报文段;而采用SACK,ACK可包含额外信息,使得发送端在每个RTT时间内可以填补多个空缺。
(4)伪超时和重传
—伪重传:没有出现数据丢失而引发的重传。
—伪重传的主要原因是伪超时,其他因素还包括包失序、包重复、ACK丢失。
—处理伪超时问题提出了许多方法,这些方法通常包含检测算法和响应算法:
· 检测算法用于判断某个超时或基于计时器的重传是否真实,一旦认定出现伪超时则执行响应算法;
· 响应算法用于撤销或减轻该超时带来的影响。
1)重复SACK(DSACK)扩展
—在SACK接收端采用DSACK,并结合通常的SACK发送端。
—DSACK的主要目的是判断何时的重传是不必要的,并了解网络中的其他事项。因此发送端至少可以推断是否发生了包失序、ACK丢失、包重复或伪重传。
—DSACK接收端允许包含序列号小于(或等于)累积ACK号字段的SACK块。
2)Eifel检测算法
—利用了TCP的时间戳选项来检测伪重传。
—在发生超时重传后,Eifel算法等待接收下一个ACK,若为针对第一次传输(即原始传输)的确认,则判定该重传是伪重传。
—利用Eifel算法比仅采用DSACK能更早检测到伪重传行为。
3)前移RTO恢复
—不需要任何TCP选项,只需要在发送端实现该方法。
—该方法只检测由重传计时器超时引发的伪重传,对其他原因引起的伪重传无法判断。
—前移RTP恢复会修改TCP的行为,在超时重传后收到第一个ACK时,TCP会发送新(而非重传)数据,之后再响应后一个到达的ACK。如果其中有一个为重复ACK,则认为此次重传没问题,如果这两个都不是重复ACK,则表示该重传是伪重传。
4)Eifel响应算法
—一旦判断出现伪重传,Eifel响应算法会引发一套标准操作。
(5)包失序和包重复
1)失序
—可能导致包失序的原因有:
· IP层不能保证包传输是有序进行的;
· 在硬件方面,一些高性能路由器会采用多个并行数据链路,不同的处理延时会导致包的离开顺序和到达顺序不匹配。
—失序问题可能存在于TCP连接的正向或反向链路中,数据段的失序和ACK的失序对TCP的影响有一定差别:
· 如果失序发生在反向ACK链路,就会使得TCP发送端窗口快速前移,接着又可能收到一些显然重复而应被丢弃的ACK。由于TCP的拥塞控制行为,这种情况会导致发送端出现不必要的流量突发行为,影响可用网络带宽。
· 如果失序发生在正向链路,TCP可能无法正确识别失序和丢包。当失序程度不是很大时,这种情况可以迅速得到处理;当出现严重失序时,TCP会误认为数据已经丢失,从而导致伪重传(主要来自快速重传算法)。
2)重复
—IP协议可能出现将单个包传输多次的情况,从而因包重复导致伪重传。
—利用SACK(特别是DSACK)可避免该问题。

10 TCP流量控制与窗口管理
(1)延时确认
—在许多情况下,TCP并不对每个到来的数据包都返回ACK,可以利用TCP的累积ACK确认。累积确认可以允许TCP延迟一段时间发送ACK,以便将ACK和相同方向上需要传的数据结合发送。
—TCP不能任意时长地延迟ACK,否则可能导致对方误认为数据丢失而出现不必要的重传。
—采用延时ACK的方法会减少ACK传输数目,可以一定程度地减轻网络负载。
(2)Nagle算法
—背景:小数据包的大量传输对于广域网来说,会加重阻塞,严重影响网络性能。
—算法内容:当一个TCP连接中有在传数据(即那些已发送但还未经确认的数据),小的报文段就不能被发送,直到所有的在传数据都收到ACK。并且,在收到ACK后,TCP需要收集这些小数据,将其整合到一个报文段中发送。
—算法特点:实现了自时钟控制,即ACK返回越快,数据传输也越快;在相对高延迟的广域网中,更需要减少微型报的数目,该算法使得单位时间内发送的报文段数目更少。也即RTT控制着发包速率。
—算法的折中:传输的包数目更少而长度更大,但同时传输时延也更长。
—Nagle算法和延时ACK结合时可能会形成一个短暂的死锁,一直持续到延时ACK计时器超时,而且,在死锁期间整个传输连接处于空闲状态,使性能变差。,如下图所示:
在这里插入图片描述
(3)滑动窗口
—每个TCP活动连接的两端都维护一个发送窗口结构和接收窗口结构。
—TCP以字节(而非包)为单位维护其窗口结构
—发送窗口结构如下:
在这里插入图片描述
—提供窗口:由接收端通告的窗口。
—可用窗口:发送端可以立即发送的数据量。计算值为提供窗口大小减去在传(已发送但还未得到确认)的数据值。
—窗口左右边界的运动:
· 关闭:即窗口左边界右移。当已发送数据得到ACK确认时,窗口会减小。
· 打开:即窗口右边界右移,使得可发送数据量增大。当已确认数据得到处理,接收端可用缓存变大,窗口也随之变大。
· 收缩:即窗口右边界左移。
—零窗口:当左右边界相等时,此时发送端不能再发送新数据。这种情况下,TCP发送端开始探测对方窗口,伺机增大提供窗口。
—接收端窗口结构如下:
在这里插入图片描述
—通过接收端窗口,可以保证其接收数据的正确性。特别是,接收端希望避免存储重复的已接收和确认的数据,以及避免存储不应接收的数据。
—只有当到达数据序列号等于左边界时,数据才不会被丢弃,窗口才能向前滑动。如果使用SACK选项,窗口内的其他报文段也可以被接收确认,但只有在接收到等于左边界的序列号数据时,窗口才能前移。
(4)零窗口与TCP持续计时器
—TCP是通过接收端的通告窗口来实现流量控制的。通告窗口指示了接收端可接收的数据量。
—当窗口值为0时,可以有效阻止发送端继续发送,直至窗口大小恢复为非零值。当接收端重新获得可用空间时,会给发送端传输一个窗口更新,告知其可继续发送数据。窗口更新通常都不包含数据(为“纯ACK”),不能保证其传输的可靠性。
—死锁:如果一个包含窗口更新的ACK丢失,通信双方就会一直处于等待状态:接收方等待接收数据,发送方等待收到窗口更新告知其可继续发送。
—为防止死锁,发送端会采用一个持续计时器间歇性地查询接收端,看其窗口是否已增长。当持续计时器超时,就会触发窗口探测的发送,强制要求接收端返回包含窗口大小的ACK。
—窗口探测包含一个字节的数据,采用TCP可靠传输,因此可以避免由窗口更新丢失导致的死锁。
—与TCP重传计时器类似,可以采用指数时间退避来计算持续计时器的超时。不同之处在于,TCP可能会放弃执行重传操作,而通常TCP不会停止发送窗口探测。
(5)糊涂窗口综合征(SWS)
—基于窗口的流量控制机制,尤其是不使用大小固定的报文段的情况,可能会出现称为糊涂窗口综合征的缺陷。
—当出现该问题时,交换数据段大小不是全长的而是一些较小的数据段。由于每个报文段中有用数据相对于头部信息的比例较小,因此耗费的资源也更多,相应的传输效率也更低。
—导致SWS出现的原因:
· 接收端的通告窗口较小;
· 发送端发送的数据段较小。
—要避免SWS问题,应遵循以下规则:
· 对于接收端来说,不应通告小的窗口值。
· 对于发送端来说,不应发送小的报文段,而且需由Nagle算法控制何时发送。
—为避免SWS问题,只有至少满足以下条件之一时才能传输报文段:
· 全长(发送MSS字节)的报文段可以发送。
· 数据段长度大于等于接收端通告过的最大窗口值的一半的,可以发送。
· 没有未经确认的在传数据时可以发送。
· 该连接禁用Nagle算法时可以发送。

11 TCP拥塞控制
—拥塞控制是TCP通信的每一方需要执行的一系列行为,用于防止网络因为大规模的通信负载而瘫痪。
—拥塞控制的基本方法是当有理由认为网络即将进入拥塞状态或者已经由于拥塞而出现路由器丢包情况时减缓TCP传输。
—拥塞控制的难点在于怎样准确地判断何时需要减缓且如何减缓TCP传输,以及何时恢复其原有的速度。
—拥塞:路由器因无法处理高速率到达的流量而被迫丢弃数据信息的现象。
(1)TCP拥塞检测
—推断是否出现拥塞,通常是看是否有丢包情况发生。
—其他检测方法还有:时延测量和显式拥塞通知(ECN),使得TCP能在丢包发生前检测拥塞。
—在当今的有线网络中,出现在路由器或交换机中的拥塞是造成丢包的主要原因;而在无线网络中,传输和接收错误是导致丢包的重要因素。
(2)减缓TCP发送
—为减缓TCP发送,需要降低发送速率,确保发送窗口大小不超过接收端接收能力和网络传输能力,即TCP发送端的发送速率等于接收速率和传输速率两者中较小值。
—拥塞窗口:反映网络传输能力的变量。
—发送端实际窗口是拥塞窗口和接收端通知窗口两者中较小者。
—发送端实际窗口的值不能过大或过小,应接近带宽延迟积(BDP),也称作最佳窗口大小。
—发送端实际窗口反映网络中可存储的待发送数据量大小,其计算值等于RTT与链路中最小通行速率的乘积。
—在网络中确定一个连接的BDP需要考虑诸多因素,如路由、时延、统计复用水平随时间的变化性等。
(3)经典算法
—获得拥塞窗口最佳值的唯一方法是以越来越快的速率不断发送数据,直到出现数据包丢失为止。
—TCP发送方的拥塞控制操作是由ACK的接收来驱动或控制的。当TCP传输处于稳定阶段,接收到ACK回复表明发送的数据包已被成功接收,因此可以继续发送操作。
—TCP拥塞控制操作是基于数据包守恒原理运行的,如下图所示,发送方发送的数据包经上通道传输给接收方,下通道传输相应ACK数据包。在高效传输的稳定状态下,上下通道都不会出现包堵塞的情况,而且在上通道中也不会有较大传输间隔。当发送方接收到一个ACK就表明可向上通道发送一个数据包。
在这里插入图片描述
—自同步:由一个ACK到达(称作ACK时钟)触发一个新数据包传输的关系。
1)慢启动
—执行慢启动的时机:
· 一个新的TCP连接的建立;
· 检测到由重传超时导致的丢包;
· TCP发送端长时间处于空闲状态也可能调用慢启动算法。
—慢启动的目的:
· 使TCP在用拥塞避免探寻更多可用带宽之前得到拥塞窗口值;
· 帮助TCP建立ACK时钟。
—初始窗口(IW):TCP以发送一定数目的数据段开始慢启动。初始值一般设为一个SMSS(发送方的最大段大小)。
—注:在大部分情况下,SMSS为接收方的MSS(最大段大小)和路径MTU(最大传输单元)两者中较小值。
—慢启动操作过程:
· 连接首先发送一个数据包,返回一个ACK;
· 接着,在第二个RTT时间内发送两个数据包,并且会接收到两个ACK。
· 依次类推,TCP发送方每接收一个ACK就会执行一次拥塞窗口的增长操作。
—注:在ACK延时情况下,如每隔一个数据包生成一个ACK,拥塞窗口仍以指数增长,但增幅较小。
—慢启动操作过程(左)及拥塞窗口随时间增长的指数函数(右)如下图:
在这里插入图片描述
2)拥塞避免
—慢启动一旦达到慢启动阈值,TCP会进入拥塞避免阶段,此时,拥塞窗口的大小随时间线性增长。如下图所示:
在这里插入图片描述
—算法的问题:
· 拥塞避免算法假设由比特错误导致包丢失的概率很小,因此有丢包发生就表明从源端到目的端必有某处出现了拥塞,而当假设不成立时,如在无线网络中,那么即使没有拥塞,TCP传输也会变慢。
· 拥塞窗口的增大可能会经历多个RTT,这就需要有充裕的网络资源,并得到高效利用。
3)慢启动和拥塞避免的选择
—在通常操作中,某个TCP连接总是选择运行慢启动和拥塞避免中的一个,不会出现两者同时进行的情况。
—具体选择方式如下:
· 当拥塞窗口小于慢启动阈值时,使用慢启动算法;
· 当拥塞窗口大于慢启动阈值时,使用拥塞避免算法;
· 当拥塞窗口等于慢启动阈值时,两种算法可任选一种使用。
—慢启动阈值不是固定的,而是随时间改变的。
—慢启动阈值的主要目的是,在没有丢包发生的情况下,记住上一次“最好的”操作窗口估计值,即它记录TCP最优窗口估计值的下界。
—如果出现重传(无论是超时重传还是快速重传)情况,TCP会认为操作窗口超出了网络传输能力范围,会将慢启动阈值更新为当前窗口大小的一半(但不小于2SMSS)。这通常会导致慢启动阈值减小,但也可能会使之增大(在TCP拥塞避免操作中,拥塞窗口的值线性增长,若拥塞窗口在一段时间后已经足够大,将阈值设为整个窗口大小的一半可能会使其增大)。
4)标准TCP
—在TCP连接建立之初首先是慢启动阶段,拥塞窗口大小等于初始窗口,慢启动阈值通常取一个较大值(至少为接收端通知窗口)。
—当接收到一个好的ACK时,拥塞窗口会进行相应更新。即当拥塞窗口小于慢启动阈值时,使用慢启动算法,窗口大小指数增长;当拥塞窗口大于慢启动阈值时,使用拥塞避免算法,窗口大小线性增长。
—当收到三次重复ACK时,会执行以下行为:
· 1、慢启动阈值(ssthresh)更新为当前窗口值得一半,但不得小于2SMSS。
· 2、启用快速重传算法,将拥塞窗口设为(ssthresh+3
SMSS)。
· 3、每接收到一个重复ACK,拥塞窗口值增加1SMSS,这也意味着能发送一个新的数据包。
· 4、当接收到一个好的(不重复的)ACK,将拥塞窗口重设为慢启动阈值。
—注:以上第2步和第3步构成了快速恢复。在恢复阶段,每收到一个重复ACK,拥塞窗口就能临时增长1SMSS,相应地就意味着能发送一个新的数据包。因此拥塞窗口在一段时间内会急速增长,直至接收到一个好的ACK。
—当由于重传超时等执行慢启动时,拥塞窗口被重设为初始窗口。
(4)对标准算法的改进
1)NewReno
—快速恢复的问题:当一个传输窗口出现多个数据包丢失时,一旦其中一个包重传成功,发送方就会接收到一个好的ACK(局部ACK),这样快速恢复阶段中拥塞窗口的暂时膨胀就会停止,而事实上丢失的其他数据包可能并未完成重传。
—改进方法:NewReno算法会记录上一个数据传输窗口的最高序列号(即恢复点),仅当接收到序列号不小于恢复点的ACK,才停止快速恢复阶段。
2)采用选择确认机制的TCP拥塞控制
—优点:发送方能够更好地确定发送哪个数据段来填补接收方的空缺。
—问题:在恢复阶段,只使用拥塞窗口作为发送方滑动窗口的界限来表示发送多少个数据包是不够的,且选择发送哪些数据包与发送时间紧密相关。
—SACK TCP强调拥塞管理和选择重传机制的分离,传统TCP则将两者结合。
—实现分离的方法:除了维护窗口,TCP还负责记录注入网络的数据量(称为管道变量)。

12 TCP保活机制
—保活机制可用于以下两种情况:
· 客户端和服务器需要了解什么时候终止进程或者与对方断开连接。
· 虽然应用程序之间没有任何数据交换,但仍然需要通过连接保持一个最小的数据流。
—保活机制是一种在不影响数据流内容的情况下探测对方的方式。它是由一个保活计时器实现的。当计时器被激发,连接一端将发送一个保活探测报文,另一端接收报文的同时会发送一个ACK作为响应。
—保活功能一般是为服务器应用程序提供的,服务器应用程序希望知道客户主机是否崩溃或离开,从而决定是否为客户端绑定资源。
—保活功能可以被设置在连接的一端、两端或者两端都没有。
—保活功能工作过程:如果在一段时间(称为保活时间)内连接处于非活动状态,开启保活功能的一端将向对方发送一个保活探测报文。如果发送端没有收到响应报文,那么经过一个已经提前配置好的保活时间间隔,将继续发送保活探测报文,直到发送探测报文的次数达到保活探测数,这时对方主机将被确认为不可到达,连接也将被中断。
—保活探测报文是一个空报文段或者只包含1字节,它的序列号等于对方主机发送的ACK报文的最大序列号减1。由于该序列号的报文已经被对方主机成功接收,从而不会对到达的报文段造成影响。并且,由于探测报文不包含任何新的有效数据,当它们丢失时也不会进行重传,从而仅凭一个没有被响应的探测报文不能断定连接是否已经停止工作。
—如果一个给定的连接在2小时内没有任何的动作,则服务器就像客户发一个探测报文段。
—TCP保活功能工作过程中,开启该功能的一端会发现对方处于以下四种状态之一:
· 对方主机仍在工作,并且可以到达。此时,TCP响应正常,请求端将保活计时器重置。
· 对方主机已经崩溃,包括已经关闭或者正在重启。此时,请求端不会接收到响应报文,请求端在超时前会持续发送通过保活探测数指定的一定次数的探测报文,如果请求端一直没有收到任何探测报文的响应,那么它将认为对方主机已经关闭,连接也将被断开。
· 对方主机崩溃并且已重启。此时,请求端会收到一个重置报文段的响应,请求端会断开连接。
· 对方主机仍在工作,但是由于某些原因不能到达请求端。由于TCP不能区分状态2和状态4,因此该情况与状态2相同。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值