因特网协议栈:运输层如何交付数据

前言

文章内容大部分来自于《计算机网络——自顶向下方法》,第七版,第3章。

运输层概览.png

形形色色的应用层协议,使不同主机间的应用可以跨越网络交换信息。这些应用各取所需,选择各自的应用层协议完成工作,并不关心数据如何在网络中传输。

运输层位于应用层与网络层之间,使用网络层的服务以支持自身工作,为应用层提供服务以支撑应用层运作。

应用层协议,面向的是应用进程间的信息交付。运输层协议面向的主机之间的信息交付。

  • 不同主机间的应用进程,彼此要交换信息,它们将通过应用层协议装填、拆解信息,也就是使用应用层的报文交互。
  • 应用层报文,需要借助运输层的能力,交付给对应的主机。对于进程来说,就要通过套接字来使用运输层的服务。
  • 最后将应用层报文,装入运输层报文中,运输层将使用网络层服务让信息跨越网络。

因此,运输层协议面向是的主机之间的信息交付,制定了主机之间如何提取信息的规则。

多路复用与多路分解

对于不同的运输层协议,主机为其分配了公知的端口收发报文(此后如无特殊说明均值运输层报文),如TCP默认端口号为80。首当其冲地,报文中需要指明主机双方各自的端口号,即源端口号(发送端)和目的端口号(接收端)。

源端口号和目的端口号,表达了多路复用与多路分解的工作目的:

  • 多路复用:报文发送端,能正确地从套接字中接受数据,封装成报文,传递到网络层,这个过程叫做多路复用。
  • 多路分解:报文接收端,从网络层中收到报文,能正确地拆解并交付给正确的套接字,这一过程叫做多路分解。

UDP

UDP全称User Datagram Protocol(用户数据报协议),以最低限度的服务来完成复用与分解功能。

UDP的特点为:

  • 尽快地交付数据,不做更多的功能支持。
  • 无须建立连接,直接向目的端口交付数据。
  • 无状态连接,不考虑数据是否正确地交付到目的地。
  • 分组首部开销小,仅用最少的字节数来支持最少的功能。

简单地说,网络层的服务提供了什么功能,UDP几乎就提供了什么功能,此外仅仅提供了简单的功能来支持复用/分解工作。UDP更多地考虑发送发及时地发送报文。

试想一下,如果你在观看直播,你更愿意的是当前发生的实时视讯情况,而不是保证的一定会让你看到的过去的视讯情况。

UDP的设计目标不需要多余的功能,也因此UDP的报文也尽可能地简单。

UDP 报文.png

  • 源端口:占16位,发送端所使用的端口,可选。如果不写入,则设置为0,如此接收端将不会发送响应。
  • 目的端口:占16位,接收端所使用的端口。
  • 长度:占16位,表示整个UDP报文所占的字节长度,最小为8,因为报文头占用了8字节。
  • 校验值:占16位,用于检验数据在传输过程中是否损坏。损坏则丢弃,不要求重新发送。

UDP面向可以容忍少量的报文丢失的场景,特别是流视频、实时电话等,对于可靠的传输要求别不高。

实现一个可靠传输协议

在更多的时候,需要一个可靠的传输协议来保证数据正确到达目的地。而为运输层协议提供服务的网络层协议,并未提供这一功能,运输层自行实现。

FSM

探讨如何实现一个可靠传输协议前,简要了解FSM(Finite-State,有限状态机)。
FSM作为一种建模工具,用来描述对象在它的生命周期过程中,所经历的状态变迁。

有限状态机.png

在FSM中包含四要素:

  • 现态:指当前所处于的状态,如当前状态为1。
  • 条件:也可以叫做事件,当一条满足时,可以执行对应的动作,或迁移到新的状态,如条件A、B。
  • 动作:当条件满足时,进行的对应处理,动作执行完后,可以保持现状,如条件C,也可以迁移到新的状态。
  • 次态:与现态是相对的,需要条件达成后激活。如现态为1,条件A满足,迁移到次态2。在状态转换完成后,现态为2。

FSM有助于说明对象如何处理复杂的条件,在各状态间变换。
现在,假定将要实现一个 Z 协议,使用FSM观察 Z 是如何一步一步完成可靠传输协议的。

Z1.0:经可靠的信道传输

在一开始,可以相信网络层提供的传输服务是可靠的。数据最终以分组的形式,通过信道发送出去。

Z1.0.png

在可靠的信道上传输报文是简单的:

  • 发送端:只需要等到条件A触发,接收来自于应用层的数据,通过信道发送分组,状态不发生改变。
  • 接收端:只需要等到条件Q触发,接收信道的数据,取出数据,交给应用层,状态不发生改变。

Z2.0:经有差错的信道顺数传输

现在,网络层提供的传输服务是不可靠的,实际也是如此,此时假设传送的分组,是按照顺序收发的。

想象一下,人们在交流时,如何确认对方接受到了信息?A向B口述了一些情况,B向A反馈“OK”表示自己已经接受到信息。

为了处理有差错的传输情况,需要引入:

  • 差错检测:需要一种机制来来验证传输的信息没有差错,需要一定的比特容量来支持这种特性。在这里,假定已经拥有了这种技术。
  • 重传:接收端发现分组出错时,要求发送端重传。
  • 接受方反馈:接收端接受到分组后,通过差错检测进行验证,如无误,回复接收端“ACK”,如有误,回复接收端“NAK”。

Z2.0.png

发送端:

  • 接收到应用层的数据后,通过信道发送分组,然后等待回复。
  • 等待回复时,如果接受到ACK,则继续处理来自应用层的数据;如果收到NAK,重新发送分组。
  • 只有确认接收端接收到报文后,才继续处理应用层的数据的行为,支持这种行为的协议也称为停等协议

接收端:

  • 接收到信道的数据,验证无误后,向发送端发送ACK,同时取出数据交给应用层。
  • 接收到信道的数据,验证有误,向发送端发送NAK。

Z2.1:确认ACK和NAK语义无误

Z2.0隐含了一个条件,假设了ACK和NAK能准确无误地传达,但他们本身也是可能出现传输错误的,因此,他们也需要进行确认。但是,不能为此建立新的“ACK”或“NAK”对它们进行确认,这种方式也避免不了新确认的丢失。

需要补充新的规则:

  • 如果没法确认对方的回答,我们将会复述一遍。类似地,如果发送端无法确定接收端的回答,认为对方没有接收到分组,那么重新发送分组。
  • 在接收端,接收到重复的分组,认为发送端没有正确接收到对于此分组的回答,重新回答ACK
  • 要满足这两个规则,需要能识别分组,因此,每个分组拥有一个编号。

目前,分组还是以顺序发送,即发送端没有确认分组正确达到接收端前,不会发送下一个分组。使用 X 和 Y 表示不同的分组。

Z2.1.png

发送端:

  • 接收到应用层的数据,通过信道发送分组 X,然后等待的描述 X 的 ACK或NAK。
  • 如果收到 NAK X 或收到的信息有问题,认为接收端没有正确收到分组,重新发送分组X
  • 如果收到 ACK X,等待接收更多的应用层数据
  • 接收到应用层的数据,通过信道发送分组 Y,然后等待的描述 Y 的 ACK或NAK。
  • 如果收到 NAK Y 或收到的信息有问题,认为接收端没有正确收到分组,重新发送分组Y
  • 如果收到 ACK Y,等待接收更多的应用层数据
  • 重复此过程

接收端:

  • 当在等待来组组信道的分组 X时,如果收到错误的分组 X,则回复 NAK X
  • 如果收到正确的分组Y,并且已拥有,认为发送发没有正确收到关于分组 Y的回复,回复 ACK Y
  • 如果正确收到分组X时,回复 ACK X, 等待来自信道的分组 Y
  • 当在等待来组组信道的分组 X时,如果收到错误的分组 Y,则回复 NAK Y
  • 如果收到正确的分组X,并且已拥有,认为发送发没有正确收到关于分组 X的回复,回复 ACK X
  • 如果正确收到分组Y时,回复 ACK y, 等待来自信道的分组 X
  • 重复此过程

通过冗余ACK的方式,来解决回复在传输中可能出错的问题。

Z2.2:无NAK的确认服务

Z2.1同时维护了 ACK 和 NAK 来表示应答。逻辑上,除非能确认回复为 ACK,否则都当做 NAK 处理。因此,只需要判断接受到的 ACK 是否是期望的 ACK,其他情况均作为 NAK,如此可仅用 ACK 来确认服务。

Z2.2.png

Z2.2与Z2.1的整体情况是大致一致的。区别之处在于等待ACK时可触发的条件更变了。以等待ACK X为例,条件从 “接收到NAK X,或无法确认的回复” 更变为 “接收到ACK Y,或无法确认的回复” 。

Z3.0:经有差错和丢包的信道传输

在Z2系列的协议中,假定了收发双发总是能收到来自对方的信息,然后做出对应的处理。实际情况是,相互传输的信息,可能并不能到达目的地,这样的情况可以称为丢包。需要进一步完善协议。

发送端需要一个定时器,在定时器倒计时结束后还没有收到接收端的回复,认为分组丢失,重传分组。

对于接收端来说,无须做其他改变,收到冗余分组时,总认为是发送端没有收到回复。

Z3.0.png

发送端:

  • 发送端每次发送分组时,重启定时器,在正确接受到回复时,关闭定时器
  • 条件D和条件F为处理超时的情况,重传对应分组
  • 条件H和条件Q处理了分组超过了定时时间,但最终到达了接收端的情况,此时有可能会收到多余的ACK,但是无须处理

接收端:

  • 在2.2的基础上,无须做其他改动

于此,确认了要实现一个可靠的传输协议的要点校验和序号定时器确认

Z4.0 流水线可靠传输协议

虽然Z3.0能保证数据一定能传送到发送端,但是它有一个非常大的问题,效率太低。Z3.0是一种停等协议,即一个分组被确认正确到达前,不会发送下一个分组。在等待接收端回复的这个时间段里,发送端完全停止工作,效率低下。

更实际的方式是,发送端并发地发送多个分组,看起来像是将分组填充到一条流水线中,故这样的技术也叫流水线

流水线.png

相对于收发两方处理分组来说,分组的传输时间要长得多,流水线的方式将有效提高效率。现在需要补充规则,以满足流水线:

  • Z3.0的版本里,只支持两个序号”X、Y”来满足确认一个分组正确收到再发送下一分组的功能。在流水线里,需要更多的序号范围来支持多个分组的确认。
  • 发送端需要对分组进行一定量的缓存,以能重新发送;接收端也需要一些冗余,以正确回复发送发重新发来的分组。
  • 对于序号范围内的分组丢失、损坏、延迟处理,流水线能选择的策略有回退N步(Go-Back-N,GBN)选择重传(Selective Repeat,SR)

Z4.0 选择回退N步来支持流水线。

回退N步.png

在回退N步的策略中,使用发送窗口的概念,以控制发送端流水线能发送多少个分组。发送端中的分组具有四种不同的状态

  • 已被确认:已经发送出去,并且收到接收端的确认的分组
  • 发送,未确认:已经发送出去,但是未收到接收端确认的分组
  • 已处理,未发送:即将发送出去的分组
  • 未处理:上一层还要发送的数据,但发送端还不能进行处理

窗口具有长度N,代表同时能有多少个分组发送到网络中,base处为窗口的左边缘,小于base的分组均是已经被确认的分组。base与nextseqnum间的分组均为等待接收端确认的分组,nextseqnum – base < N 则代表发送端还能继续发送分组。

对于接收端来说,维护一个序号X,代表X以内的分组均已接收,正确收到一个分组时,回复 ACK X。如此,发送端知道发送端期望序号为X+1分组,然后调整base到X+1,发送X+1后的分组。FSM就变成了:

Z4.0.png

发送端:

  • 从base起,发送至base+N的分组,然后启动定时器,以nextseqnum记录发送到了哪个分组。
  • 超时时,重新从base起,发送至base+N的分组。
  • 收到无法确认的回复时,什么也不做。
  • 收到确认回复X时,base更新到X+1,发送base到base+N的分组,启动定时器。如果base=nextseqnum,关闭定时器。

接收端:

  • 维护X,表示已经接收到的分组序号范围。
  • 收到正确的期望的分组时,取出数据交付给上层,同时更新X,然后回复ACK X。
  • 其他情况,直接回复 ACK X。也包括收到乱序的分组时,会丢弃不要,在发送端接收到回复后,会重新发送。

Z5.0 选择重传的可靠运输协议

虽然Z4.0回退N步的方式,能满足流水线,但是它很大的一个问题在于,浪费太多带宽,某个分组的丢失或ACK损坏,都可能导致重传很多分组的资源浪费。选择重传仅传输丢失的分组,解决带宽浪费的问题。

选择重传.png

要支持选择重传,在接收端也要使用窗口的概念,来累计记录自己收到的分组,使用rcv_base记录窗口的左边缘。对于发送端来说,就要为每个分组,单独地启用定时器。接收端在接受到乱序的分组,如果分组没有并在窗口范围内,将缓存起来,回复ACK X。接收端将参照 X,更新自己的send_base值,并做出对应的动作。FSM就变成了:

Z5.0.png

发送端:

  • 发送分组,为此分组启动定时器,更新nextseqnum,如果send_base + N > nextseqnum,重复此过程。
  • 当分组X超时,重新发送此分组,重启此分组的定时器。
  • 收到ACK X时,标记X为已确认,当send_base=X时,将窗口滑动到最小序号的未确认分组下,更新send_base,发送窗口条件下的分组。
  • 其他情况不做任何处理。

接收端:

  • 收到分组X并确认无误,首先判断分组是否在窗口范围内,如果在,更新为已接收,如果没有缓存则进行缓存。而当 rcv_base = X 时,更新rcv_base滑动窗口到最小的没有缓存的分组序号下,将滑过的缓存分组交付给上层,回复ACK X。
  • 其他情况不做任何处理。

小结

到此,就实现了一个具有基本效率的可靠传输协议,它所需具有的基本条件为:

  • 检验和:检测一个分组是否在传输中受损。
  • 定时器:定时器解决了分组丢失、ACK丢失或受损的问题,以向接收端再次发送分组以确保分组传输到接收端。
  • 序号:将分组标识,得以将多个分组同时在网络中传输,并能针对每一个分组进行确认。
  • ACK:接收端告知发送端分组正确收到的行为,方式可能有差异,但目的一致。
  • 流水线:使多个分组同时在网络中传输,提高效率。
  • 窗口:使用累计确认的方式,使得支持流水线,在实际环境中,还有更进一步的作用。

在以FSM观察可靠传输协议的模型是如何形成过程之后,现在能更充分地理解TCP是如何实现的。

TCP

TCP(Transmission Control Protocol)全称为传输控制协议。TCP是面向连接的可靠传输协议。TCP旨在将数据正确地在主机间交付,并尽可能地保证收发双端效率,提供各式各样有特点的额外功能。

TCP报文结构

TCP报文结构.png

一个TCP报文包括:

  • 源端口号:发送端端口,用于多路复用
  • 目的端口号:接收端端口,用于多路分解
  • 序号:在TCP中,每个数据字节占一个序号,这里的序号就表示,当前报文携带的数据是一组数据中的起始位置,比如当前序号为300,一共有100字节,那么下一个报文的序号为400
  • 确认号:为ACK序号,表明下一个期望收到的序号X,意味为X之前的数据都已正确接收到
  • 首部长度:因为存在可选的选项字段,因此用来确认整个头部的长度
  • 保留使用:为将来可能的新用途而做的预留
  • 标志位:包含了URG、ACK、PSH、RST、SYN、FIN六个bit的标志位控制功能,如当ACK被置位1时,确认号才有效
  • 接收窗口:用来告诉发送端,接收端的窗口大小,以能调节发送数据的速率,达到流量控制的目的
  • 因特网校验和:由发送端计算和存储,用来给接收端验证报文是否损坏
  • 紧急数据指针:只有URG置为1时才有效。紧急数据的偏移位置,是发送端向接收端紧急发送数据的一种方式
  • 选项:可选部分,用来协商发送方与接受方的最大报文长度,或者为调节窗口做调节因子
  • 数据:可选部分,用来携带应用层数据,或做他用的其他数据。

建立连接

发起连接的一方为客户端,另一方为服务端。TCP建立连接的过程也被三次握手

三次握手.png

第一次握手
客户端向服务端发送一个特殊的报文,报文不携带任何应用层数据。首先,将SYN标志位置位1,表示要与服务端建立连接的功能,也因此这个特殊报文也叫做SYN报文。然后,随机生成一个初始序号 client_isn 并放入序号字段中。最后,通过下层协议发送出去。

第二次握手
服务端收到报文后,通过SYN标志位识别出是SYN报文,直到客户端要与它进行连接。接着,服务端为这个TCP连接分配缓存和变量,为后续内容服务。然后,服务端也生成一个不包含数据的报文,将SYN标志位置位1,确认号填充 client_isn + 1,在序号填充自己的初始序号 client_isn。最后,将报文发送出去,这个表明允许连接的报文也叫做SYNACK报文。

第三次握手
客户端收到SYNACK报文后,通过确认号确认连接,为TCP连接分配缓存和变量。现在开始,客户端可以开始向服务端发送数据。与此同时,连接已经建立了,SYN标志位置位0。下一个报文中,在确认号中填充 service_isn + 1以让服务器端对允许连接的报文得到确认。

TCP连接建立之后,双方就可以持续地向对方发送数据,TCP的数据发送是双向的,也是为什么双方要交换初始序号,并为对方分配缓存的变量。

发送数据

以客户端向服务端发送数据来观察TCP发送数据。

TCP发送数据.png

  • 客户端向服务端发送数据,TCP报文在序号段填充,如第一条报文填充了0
  • 服务端收到数据后,向客户端回复ACK,在报文确认号填充,如第一条回复报复填充了1000
  • TCP采取了累计确认,服务端的ACK 4000 回复丢失了,因此在超时后,客户端重新发送的数据 “Seq=3000,1000字节数据”
  • 虽然 ACK 2000 的报文也丢失了,但是在超时前,ACK 3000 的报文抵达了客户端,因此客户端知道 序号3000以前的数据都正确交付,没必要再重传。

断开连接

某一时刻,客户端不再需要向服务端传输数据,选择与服务端断开连接,以节省各自的开销。TCP断开连接的过程也称四次挥手

TCP四次挥手.png

  1. 客户端向服务端发送一个特殊的TCP报文,将FIN置为1,指定一个序号client_num。
  2. 服务端收到服务端的报文断开连接报文后,回复ACK,确认号为 client_num + 1
  3. 在服务端处理好自身逻辑后,也向客户端发送一个断开连接报文,FIN置为1,指定一个序号server_num
  4. 客户端收到断开连接报文后,回复AC,确认号为 client_num,序号为 client_num+1
  5. 至此双方断开连接

特别需要注意的,客户端需要确认服务端收到了自己的ACK报文才能断开连接,但断开连接的服务端不再向客户端发送报文,那么客户端如何确认?

MSL(Maximum Segment Lifetime,最长报文寿命),是指任何报文在网络上的最长时间,超过这个时间的报文将会被丢弃。

客户端在发送ACK后,等待2MSL时间,确认没有再次收到服务端的FIN报文,再次关闭连接。因为当服务端没有收到来自客户端的ACK,会在超时时间后重新发送FIN报文,客户端在收到后,重新回复ACK,并重新等待2MSL。由此,客户端得以确认服务端连接关闭,随之关闭自己的连接。

整体来看TCP从建立连接到断开连接的状态变迁可用下图表示,不赘述。

TCP 整体FMS.png

流量控制与拥塞控制

现在为止所说的TCP内容,假设了网络十分通畅,双方可以以任意速率传输内容。而实际情况是,网络并不具备满足任意速率的传输条件。

当TCP运作在拥挤的网络上,可以想见的是,发送端的报文将不能按时交付到接收端,或者接收端的ACK报文也不能快速地通知到发送端。对于发送端来说,会认为报文丢失了,频繁地触发报文重发,而重发的报文也面临相同的情况。在这样的条件下,与其保持速率发送报文浪费带宽、浪费端能力且变得没有效率,不如主动减低速率来保持相对效率。

更进一步地,如果网络通畅,发送端能快速地发送报文,但接受方处理报文的能力远远不急,也将导致接收方缓存溢出,将丢弃暂时无法处理的新报文,进而导致发送方的超时重发。容易想到,双发的速率匹配,更能有效率地工作。

流量控制服务用于解决双方速率匹配的问题以消除接收方缓存溢出的可能性,拥塞控制则用于解决如何让发送速率与网络情况相匹配的问题。虽然两者的应对方式十分相似,但是是为了不同的目的而采取的措施。

流量控制

接收窗口.png

流量控制服务,在接收端中使用接收窗口来表示接收端余下的处理数据的能力,以达到协商控制。

在TCP建立后,接收端会建立缓存来接收数据并交付给应用层,一旦缓存溢出,新的数据则不再能进来。

接收端:
① 使用 LastRead 表示接收端的应用程序从缓存中读取的数据位置
② 使用 LastReceived 表示接收端从发送端收到的数据的位置
③ 缓存的容量为 BufferSize
要使缓存不溢出,则 LastReceived - LastRead <= BufferSize

④ 接收窗口大小用 rwnd 表示,理解为缓存余下的空间
rwnd = BufferSize -(LastReceived - LastRead)
将rwnd放到TCP报文的接收窗口段中。

发送端:
① rwnd是动态的,需要跟踪,也就是在发送端也有一个映射
② LastAck 表示已确认的交付的数据的位置
③ LastSend 表示已发送的数据的位置
要使缓存不移除,则 rwnd <= LastSend - LastAck
复制代码

如此,双方各自维护关于接收窗口大小rwnd的信息,并通过TCP报文持续更新信息,得以消除缓存缓存溢出的影响。

值得注意的,当rwnd=0时,接收端可能不再能接受到发送端发来的ACK,因为按照规则,在接收端没有更多的处理能力时,发送方不应发送更多数据。为了消除这个影响,当rwnd=0时,发送端将继续发送1字节的数据,以能更新rwnd,让工作继续下去。

拥塞控制

拥塞控制是为了使发送方的发送速率,与网络情况相匹配。如果发送方的速率大于网络所能提供的速率,将容易导致分组丢失,或分组不能按时交付而引起超时。

现在,假设接收方的缓存是充足的,即rwnd是足够的,现在发送方的发送速率,取决于网络通畅情况。

拥塞控制要面对的三个问题是:

  1. 发送方要如何控制速率,来发送分组
  2. 发送方如何得知网络情况
  3. 发送方以什么方式调整速率

对于第一个问题,在实现Z4.0之后的协议模型中,使用了发送窗口(cwnd)的概念表示了发送方剩余的发送分组的能力,那么,LastSend – LastAck <= min(cwnd, rwnd)。现在,仅考虑 cwnd,即改变cwnd,就能控制发送方的发送速率。

对于第二个问题,一个正确的ACK,隐喻网络是通畅的,能准时地交付分组,可以加快速率。而一个丢失的分组将使发送方收到重复的ACK,重传分组。超时也代表分组没有在预期时间内交付,需要重传。参照这样的逻辑,当发送方发生一个超时,或3个重复ACK时,认为网络是拥塞的,需要降低速率。

对于第三个问题,需要在真实的网络环境下取得平衡,如果过快地调整发送速率,引起过多的丢失而浪费带宽能力;如果过于谨慎地调整发送速率,则不能充分地利用带宽。因此,调整速率的算法要在两者之间平衡。TCP拥塞控制算法提供了足够好的解决方案。

拥塞控制算法FSM.png

在TCP拥塞控制算法中,发送方将在三个状态中切换,不断调整以适应网络。

慢启动

发送方以慢启动开始。cwnd 将被设置为 1个 MSS 。MSS为报文所能承载的最大数据长度,报文的往返时间为 RTT,发送速率为 MSS / RTT。ssthresh为阈值,即当cwnd与ssthresh满足一定关系后,发送方将切换状态。

  • 在慢启动时,发送方希望快速地提升发送能力,能个RTT时间中,发送达到 cwnd 的分组。在每一个新的ACK到来时,cwnd = cwnd + MSS ,这样,在每一个RTT时间后,cwnd 翻倍。因此,发送速率呈指数增长。
  • 发送速率将很快超过网络情况,发送方将收到重复的ACK,dupACKcount++。
  • 如果发生超时,说明在慢启动的过程中。网络情况发送了剧烈的变化,这样的况下,切换到其他状态并不合适,dupACKccount = 0,ssthresh = cwnd / 2,发送丢失的分组,重新进行慢启动。
  • 如果 dupACKccount = 3,说明发送速率超过了网络情况,切换到快速回复继续调整。
  • 如果 cwnd >= ssthresh,说明发送速率还有提升空间,但是继续翻番过于鲁莽,切换到拥塞避免继续调整。

拥塞避免

拥塞避免说明发送方速率还有提升空间,但是需要采取更谨慎地策略提升速率,尽可能地减少提升速率后可能引起的分组丢失。

  • 当收到新的ACK时,与慢启动在每个RTT时间翻番不同,拥塞避免在每个RTT时间增加1个MSS,即每个新的ACK到来cwnd增加量为MSS * (MSS / cwnd)。
  • 收到重复的ACK时,dupACKcount++。
  • 在发生超时,说明在速率线性增长的过程中,网络情况发生了剧烈的变化,将dupACKccount = 0,ssthresh = cwnd / 2,发送丢失的分组,然后进入慢启动状态,重新快速匹配速率。
  • 当 dupACKccount = 3,说明发送方速率可能稍微超过了网络情况,将 ssthresh = cwnd / 2,cwnd = sshresh + 3 * MSS,发送丢失的分组,进入快速恢复状态。

快速恢复

快速恢复状态是不一定具有的状态,它的意义为,快速地调整判断,是让发送方重新进入慢启动,以重新快速定位网络的大致情况,还是重新进入拥塞避免,谨慎地调整发送速率。

  • 在收到重复的ACK时,cwnd = cwnd + MSS,发送新分组。
  • 在收到新的 ACK 时,将 cwnd = sstresh , dupACKccount = 0,进入拥塞避免
  • 在超时时,重新发送丢失的分组,ssthresh = cwnd / 2,cwnd = 1 MSS。dupACKcount = 0,重新进入快启动。

TCP拥塞控制算法以慢启动拥塞避免快速恢复三种不同状态下的处理,帮助发送方动态地适配网络情况,并在网络发生剧烈变动时也能迅速适应。

总结

  1. 从一开始,从多路复用与多路分解,阐述了一个运输层协议最基本的功能,即知道运输层协议所运载的数据从哪来,到哪去。为应用层服务。
  2. 借助UDP,观察了一个最简单的运输层服务应具有的功能,也侧面说明了运输层所依赖的网络服务,不能保证数据可靠性。
  3. 运输层有时需要可靠的数据传输服务,通过Z协议的实现模型,说明了检验和ACK序号超时发送窗口是实现一个可靠传输协议的基本要素。
  4. 最后,通过观察 TCP 的实现,其具有包括Z协议模型所有的特点及其他特点,如面向链接

流量控制拥塞控制等

总地来说,运输层协议规定了主机与主机间如何交换信息,为应用层的运作提供了可能。

参考

《计算机网络——自顶向下方法》,第七版,第3章

面试官,不要再问我三次握手和四次挥手

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享