Introduction and Transport-Layer Services

运输层位于应用层和网络层之间,该层为运行在不同主机上的应用进程提供直接的通信服务,它将网络层的在两个端系统之间的交付服务扩展到运行在两个不同端系统上的应用进程之间的交付服务。这句话的理解是,运输层协议为运行在不同主机上的应用进程之间提供了逻辑通信(logic communication)功能,应用程序使用运输层提供的逻辑通信功能彼此发送报文,而无需考虑承载这些报文的物理基础设施的细节。

运输层协议是在端系统中而不是在路由器中实现的。在发送端,运输层将从发送应用进程接收到的报文转换成运输层分组,该分组称为报文段(segment)。实现方式可能是将应用报文划分为较小的块,并为每块加上一个运输层首部以生成运输层报文段,然后在发送端系统中,运输层将这些报文段传递给网络层。注意:网络路由器仅作用于该数据报的网路层字段;即它们不检查封装在该数据报的运输层报文段的字段。在接收端,网络层从数据报中提取出运输层报文段,并将该报文段上交给运输层,经运输层处理后上交给应用进程使用。

Relationship Between Transport and Network Layers

运输层位于网络层之上。网络层提供了主机之间的逻辑通信,而运输层为运行在不同主机的进程之间提供了逻辑通信。运输层协议只工作在端系统中,在端系统中,运输层协议将来自应用进程的报文移动到网络边缘(即网络层),但对这些报文在网络核心如何移动并不做任何规定。中间路由器既不处理也不识别运输层加在应用层报文的任何信息。

运输层协议常常受制于底层网络协议的服务模型。但即使底层网络协议是不可靠的,会使分组丢失、篡改和冗余,运输层协议也能为应用程序提供可靠的数据传输服务。

Overview of the Transport Layer in the Internet

因特网为应用层提供了两种截然不同的可用运输层协议,一个是UDP(用户数据报协议),它为调用它的应用程序提供一种不可靠的、无连接的服务;另一个是TCP(传输控制协议),它为调用它的应用程序提供一种可靠的、面向连接的服务。

在讲UDP和TCP之前,需要简单了解网络层。网络层协议非常重要的是IP,即网际协议。IP为主机之间提供逻辑通信,IP的服务模型是尽力而为交付服务(best-effort delivery service),即它不确保报文段的交付,不保证报文段的按序交付,不保证报文段中数据的完整性,因此IP被称为不可靠服务(unreliable service)。

再来看UDP和TCP,两种协议的基本责任是将两个端系统间IP的交付服务扩展为运行在端系统上的两个进程间的交付服务。将主机间交付扩展到进程间交付被称为运输层的多路复用(transport-layer multiplexing)与多路分解(demultiplexing)。UDP和TCP还可以通过在其报文段首部中包括差错检查字段而提供完整性检查。进程到进程的数据交付和差错检查是两种最低限度的运输层服务,也是UDP能提供的仅有的两种服务。

另一方面,TCP为应用程序提供几种附加服务。一是可靠数据传输(reliable data transfer),通过使用流量控制、序号、确认和定时器,TCP确保正确地、按序地将数据交付;另一个是拥塞控制(congestion control),它防止任何一条TCP连接用过多流量来淹没通信主机之间的链路和交换设备。

Multiplexing and Demultiplexing

一个主机有一个或多个进程,而一个进程有一个或多个套接字,将运输层报文段中的数据交付到正确的套接字的工作称为多路分解(demultiplexing);在源主机从不同套接字中收集数据块,并为每个数据块封装上首部信息从而生成报文段,然后将报文段传递到网络层,所有这些工作称为多路复用(multiplexing)。

要实现多路复用,运输层需要:套接字有唯一的标识符;每个报文段有特殊字段来指示该报文段所要交付到的套接字。如图2.1,这些特殊字段是源端口号字段(source port number filed)和目的端口号字段(destination port number filed)。端口号是一个16比特的数,大小在0~65535之间。0~1023范围的端口号被称为周知端口号(well-known port number),是受限制的,保留给如HTTP等周知的应用层协议使用。当我们开发一个新的应用程序时,必须为其分配一个端口号。

clip_image002

​ 图2.1 运输层报文段中的源与目的端口号字段

因此多路分解就是,在报文段到达主机时,运输层检查报文段中的目的端口号,将其定位到相应的套接字。UDP基本上就是这样做的,但TCP的却更为复杂。

无连接的多路复用和多路分解

无连接的多路复用和多路分解,即UDP多路复用和多路分解。复用与分解的关键在于为套接字关联一个特定的端口号。在使用UDP通信时,创建一个UDP套接字,运输层可以自动为该套接字分配一个端口号,也可以手动为该套接字绑定一个特定的端口号。在形成运输层的报文段时,其中包括应用程序数据、源端口号(作为“返回地址”)、目的端口号和两个其他值。这样就能够精确描述UDP的复用与分解。

需要注意的是,一个UDP套接字是由一个二元组全面标识的,该二元组包含了一个目的IP地址和一个目的端口号。因此,如果两个UDP报文段有不同的源IP地址和源端口号,但是具有相同的目的IP地址和目的端口号,那么这两个报文段将通过相同的目的套接字****被定向到相同的目的进程,**即目的主机只使用目的端口号和IP地址定位相应的套接字。这一点与TCP是不同的。

面向连接的多路复用与多路分解

TCP套接字与UDP套接字不同的是,因为TCP是面向连接的,**TCP套接字是由一个四元组(源IP地址,源端口号,目的IP地址,目的端口号)来标识的。**因此,当一个TCP报文段从网络到达主机时,该主机使用全部4个值来将报文段定向到相应的套接字。比如,两个具有不同源IP地址或端口号的TCP报文段将被定向到两个不同的套接字,除非TCP报文段携带的是初始创建连接的请求(因为TCP服务器有一个“欢迎套接字”,TCP连接建立时都需要先向该套接字发送请求)。

服务器主机可以支持很多并行的TCP套接字,每个套接字与一个进程相联系,并由其四元组来标识每个套接字。当一个TCP报文段到达主机时,所有4个字段被用来将报文段定向分解到相应的套接字。

端口扫描器nmap能够扫描能够接收TCP连接或能响应的UDP端口。

如图2.2,主机A和主机C以及服务器B都有自己的唯一IP地址A、B、C,其中主机C向服务器B发送两个会话,主机A向服务器B发送一个会话。主机C为两个会话分配了两个不同的源端口号(26145和7532),因为主机A选择源端口号时与主机C互不相干,因此它也可以将源端口号26145分配给其会话连接。尽管如此,服务器B仍能正确地分解这两个具有相同源端口号的连接,因为两个连接的源IP地址不同。

clip_image003

​ 图2.3 两个客户使用相同目的端口号和源端口号与同一服务器应用通信

Web服务器与TCP

需要注意的是,**连接套接字并非与进程之间并不是一一对应关系。**早期每个Web服务器可以为每条连接生成一个新进程,这样每个进程都有自己的连接套接字,但现在的高性能Web服务器通常只使用一个进程,当客户请求连接时,这个进程会为每个新的客户创建一个具有新连接套接字的新线程,因此很多具有不同标识的的连接套接字连接到的是相同的进程。

Connectionless Transport: UDP

运输层的最低限度是必须提供一种复用/分解服务,以便在网络层和正确的应用级进程之间传递数据。UDP就是一种非常简单的协议,在[RFC 768]的定义中,UDP除了复用/分解以及少量差错检测之外,几乎没有对IP增加别的东西。UDP从应用进程得到数据,附加上用于复用/分解的源和目的端口号字段,以及两个其他的小字段,然后形成报文段交给网络层。UDP做了非常少的工作,差不多应用进程是直接与IP交互。

使用UDP时,在发送报文前,发送方和接收方的运输层实体之间没有握手,正因如此,UDP被称为是无连接的。

DNS是一个通常使用UDP的应用层协议的例子。

许多应用更适合使用UDP,主要原因有:

(1)关于发送什么数据以及何时发送的应用层控制更为精细。采用UDP时,只要应用进程将数据传递给UDP,UDP就会将该数据打包进UDP报文段并传递给网络层。而TCP提供可靠传输服务,还有拥塞控制机制和超时重传机制,TCP不管可靠交付需要多长时间,一定要保证目的主机接收并确认。而实时应用通常要求最小的发送速率,不希望过分地延迟报文段的传送,且能容忍一些数据的丢失,TCP服务模型并不是特别适合这些应用的需要。这些应用可以使用UDP,并作为应用的一部分来实现所需、超出UDP的不提供不必要的报文段交付服务之外的额外功能。

(2)**无须建立连接。**UDP不需要任何准备即可进行数据传输,因此UDP不会引入建立连接的时延(这可能是DNS运行在UDP上的主要原因)。

(3)**无连接状态。**TCP需要在端系统中维护连接状态,该状态包括缓存、拥塞控制参数以及序号确认序号。**而UDP不需要维护连接状态,**也不跟踪这些参数。因此,某些专门用于某种特定应用的服务器当应用程序运行在UDP之上而不是运行在TCP上时,一般都能支持更多活跃客户。

(4)**分组首部开销小。**每个TCP报文段都有20个字节的首部开销,而UDP仅有8字节的开销。

UDP不提供可靠数据传输服务,但是使用UDP的应用是可能实现可靠数据传输的。这可以通过在应用进程自身中建立可靠性机制来完成,(例如,可通过增加确认和重传机制来实现)如谷歌浏览器中的QUIC协议就是在UDP之上的应用层协议实现了可靠性。这样做可以使应用进程进行可靠通信,而无需受制于TCP的拥塞控制机制带来的传输速率限制。

UDP Segment Structure

UDP首部只有4个字段,每个字段由两个字节组成。源端口号和目的端口号在复用/分解时被使用;长度字段指示了在UDP报文段中的字节数(首部+数据),因为数据字段的长度在一个UDP段中不同于在其他层封装后的段中,所以需要一个明确长度;接收方使用校验和来检查在该报文段是否出现差错。

image

​ 图2.1 UDP报文段结构

UDP Checksum

UDP提供了差错检测功能,具体为发送方的UDP对报文段中的所有16比特字段的和进行反码运算,求和时遇到的任何溢出都被回卷。得到的结果被放在UDP报文段中的检验和字段。

用一个例子说明计算过程,有三个16比特:

clip_image002

最后一次加法有溢出,它要被回卷,其结果进行反码运算后得到(1011010100111101)校验和。在接收方,包括校验和的全部的4个16比特加在一起,若没有出现差错,最后结果将是(1111111111111111)。

UDP提供端到端的差错检测,但不能对差错进行恢复,某些实现是将受损报文段丢弃,其他实现是将受损报文段交给应用程序并给出警告。

Principles of Reliable Data Transfer

为上层实体提供的服务抽象是:数据可以通过一条可靠的信道进行传输。实现这种服务抽象是可靠数据传输协议 (reliable data transfer protocol) 的责任。

由于可靠数据传输协议的下层协议也许是不可靠的,因此这是一项困难的任务。TCP是在不可靠的 (IP) 端到端网络层之上实现的可靠数据传输协议。

9rTshXF.png

Building a Reliable Data Transfer Protocol

1 经完全可靠信道的可靠数据传输:rdt1.0

假设底层信道是完全可靠的,此时协议为rdt1.0。有限状态机(Finite-State-Machine,FSM)

88p9BlE.png

该发送方和接收方的FSM每个都只有一个状态。FSM描述图中的箭头指示了协议从一个状态变迁到另一个状态(上图每个FSM都只有一个状态,因此变迁的必定是从一个状态返回到自身。)

引起变迁的事件显示在表示变迁的横线上方,事件发生时所采取的动作显示在横线下方。如果对一个事件没有动作,或没有事件就在横线上方或者下方用^符号表示。

1)在发送端:rdt的发送端只通过rdt_send(data)事件接收来自较高层的数据,产生一个包含该数据的分组(经由make_pkt(data)动作),并将分组发送到信道中。实际上,rdt_send(data)事件是由较高层应用过程调用产生的。

2)在接收端:rdt通过rdt_rcv(packet)事件从底层信道接收一个分组,从分组中取出数据(经由extract(packet,data)动作),并将数据上传给较高层(通过deliver_data(data)动作)。实际上,rdt_rev(packet)事件是由较底层协议的过程调用产生的。

2 经具有比特差错信道的可靠数据传输:rdt2.0

底层信道更为实际的模型是分组中的比特可能受损。在分组的传输、传播或缓存的过程中,这种比特差错通常会出现在网络的物理部件中。此时仍然假定所有发送的分组(虽然有些比特可能受损)将按其发送的顺序被接收。

利用控制报文使得接收方可以让发送方知道哪些内容被正确接收,哪些内容接收有误并因此需要重复。在计算机网络中,基于这样重传机制的可靠数据传输协议称为**自动重传请求(Automatic Repeat reQuest,ARQ)**协议。

ARQ协议还需要另外三种协议来处理存在比特差错的情况:

1)差错检测:这些技术需要有额外的比特(除了待发送的初始数据比特之外的比特)从发送方发送到接收方;这些比特将被汇集在rdt2.0数据分组的分组检验和字段中。

2)接收方反馈:rdt2.0协议将从接收方向发送方回送ACK(“肯定确认”)或者NAK(“否定确认”)分组。理论上,这些分组只需要一个比特长;用0表示NAK,用1表示ACK。

3)重传:接收方收到有差错的分组时,发送方将重传该分组文。 OoF58nx.png

rdt2.0的发送端FSM有两个状态,接收方FSM有一个状态

首先,发送端协议正等待来自上层传下来的数据。当产生rdt_send (data)事件时,发送方将产生一个包含待发送数据的分组,带有检验和,然后经由 udt_send(sndpkt)操作发送该分组。然后,发送方协议等待来自接收方的ACK或NAK分组。如果收到一个ACK 分组,则发送方知道最近发送的分组已被正确接收,因此协议返回到等待来向上层的数据的状态。如果收到NAK分组,该协议重传最后一个分组并等待接收方的响应。

但是注意以下事实:

1)当发送方处于等待ACK或NAK的状态时,它不能从上层获得更多的数据。这就是说rdt_send()事件不可能出现,仅当接收到ACK并离开该状态时才能发生这样的事件。因此,发送方将不会发送一块新数据,除非发送方确信接收方已正确接收当前分组。rdt2.0协议被称为停等(stop-and-wait)协议。

2)它存在一个致命的缺陷,尤其是没考虑到ACK或NAK分组受损的可能性。

解决这个新问题的一个简单方法(几乎所有现有的数据传输协议中,包括 TCP,都采用了这种方法)是在数据分组中添加一新字段,让发送方对其数据分组编号,即将发送数据分组的序号放在该字段。于是,接收方只需要检查序号即可确定收到的分组是否一次重传。因为目前我们假定信道不丢失分组。ACK 和 NAK 分组本身不需要指明它们要确认的分组序号。 发送方知道所接收到的 ACK 和 NAK 分组(无论是否是含糊不清的)是为响应其最近发送的数据分组而生成的。

yMnU15e.png

2qQNPD0.png

下面是rdt2.2的FSM描述:

uuq9awx.png

O73tMVL.png

3 经具有比特差错的丢包信道的可靠数据传输:rdt3.0

现在假定除了比特受损外,底层信道还会丢包。协议现在必须处理另外两个关注的问题:怎样检测丢包以及发生丢包后该做些什么。在rdt2.2中已经研发的技术:使用校验和、序号、ACK分组和重传等。使得可以解决第二个问题,对于第一个问题,还需要增加一种新的协议机制。

有很多可能的方法用于解决丢包问题(在本章结尾的习题中研究了几种其他方法)。在这里,我们让发送端负责检测和恢复丢包工作。假定发送端传输一个数据分组,该分组或者接收端对该分组的 ACK 发生了丢失。在这两种情况下,发送端都收不到应当到来的接收端的响应。

因此实践中采取的方法是发送方明智地选择一个时间值,以判定可能发生了丢包(尽管不能确保)如果在这个时间内没有收到ACK,则重传该分组。 注意,如果一个分组经历了一个大的时延,发送方可能会重传该分组,既是数据分组和ACK均没有发生丢失。这就需要考虑冗余数据分组的可能性。rdt2.2协议已经有足够的功能(即序号)来处理分组情况,接收方可丢弃重复冗余分组。

为了实现基于时间的重传机制,需要一个倒计数定时器,在一个给定的时间量过期后,可中断发送方。因此,发送方需要能做到: ①每次发送一个分组(包括第一次分组和重传分组)时,便启动一个定时器。②响应定时器中断(采取适当的动作) ③终止定时器

rdt3.0有时被称为比特交替协议(alternating-bit protocol)

CwR3zp6.png

数据传输协议的要点:在检验和、序号、定时器、肯定和否定确认分组这些技术中,每种机制都在协议的运行中起到了必不可少的作用。

uXjj0Db.png

Pipelined Reliable Data Transfer Protocols

rdt3.0 性能问题的核心在于它是一个停等协议。

stop-and-wait.jpg

pipelined.jpg

解决这种特殊的性能问题的一个简单方法是:不使用停等方式运行,允许发送方发送多个分组而无需等待确认。这种技术为流水线 (pipeline):因为许多从发送方向接收方输送的分组可以被看成是填充到一条流水线中。

流水线技术对可靠数据传输协议带来如下影响:

1)必须增加序号范围:因为每个输送中的分组必须有一个唯一的序号,而且也许有多个在输送中未确认的报文。

2)协议的发送方和接收方两端也许必须缓存多个分组。

3)所需序号范围和对缓冲的要求取决于数据传输协议如何处理丢失、损坏及延时过大的分组。

解决流水线的差错恢复有两种基本的方法:回退N步(G0-Back-N,GBN),和选择重传(Selective Repeat,SR)

Go-Back-N (GBN)

在回退N步协议中,允许发送方发送多个分组(当有多个分组可用时)而不需等待确认,但它也受限于在流水线中未确认的分组数不能超过某个最大允许数N。建议操作本书配套Web网站上的GBN Java小程序(这是个非常好的Java程序)。

Network_GBN-sender.png

base对应的分组被确认之后,窗口才会向右移动。N被称为窗口长度。限制窗口长度是要进行流量控制与拥塞控制。

在实现中,一个分组的序号承载在分组首部的一个固定长度的字段中。如果分组序号字段的比特数是$k$,则该序号范围是$[0,2^k-1]$。在一个有限的序号范围内,所有涉及序号的运算必须使用模$2^k$运算。(即序号空间可被看作是一个长度为2k的环,其中序号2k-1紧接着序号0。)TCP有一个32比特的序号字段,其中的TCP序号是按字节流中的字节进行计数的,而不是按分组计数。

基于ACK、无NAK的GBN协议的发送方和接收放这两端的扩展FSM:

Network_GBN-sender(1).png

Network_GBN-receiver.png

GBN发送方必须响应三种类型的事件:

  • 上层的调用。当上层调用了rdt_send()后,GBN发送方必须先检测其发送窗口是否已满(即是否有N个已发送但未被确认的分组)。如果没有满,则产生一个分组并将其发送;如果窗口已满,则GBN发送方将数据返回(退还)上层,告诉他现在还不能发送。
  • 收到一个ACK反馈报文。在GBN协议中,对序号为n的分组采用的是累积确认(cumulative acknowledge),即发送方当收到序号为n的ACK报文时,表明接收方已经正确接收了序号n 及n以前的所有的分组。如果发送方收到了一个损坏的反馈报文,则不做任何处理,继续等待。
  • 超时处理。当GBN协议中的发送方遇到超时事件时,将会重新启动计时器,并重新发送所有已发送但未被确认的报文。发送方只有一个定时器,指明当前最早发送但未被确认的分组(基序号base);当发送方收到一个ACK,但仍有未被确认的分组时,则定时器重新被启动;但如果没有未被确认的分组,则定时器停止。

在GBN协议中,当接收方收到序号为n的分组且该分组是按序的(即上一个分组的序号是n-1),则接收方将为分组n发送一个ACK,并将该分组中的数据部分交付到上层。在所有其他情况下(序号为n的分组是失序的或是损坏的),接收方将丢弃该分组,并为最近按序接收到的分组重新发送ACK。

Selective Repeat (SR)

sr.jpg

SR接收方将确认一个正确接收的分组而不管其是否按序。失序的分组将被缓存直达所有丢失分组(即序号更小的分组)皆被收到为止。

sr-operation.jpg

sr-window-a.jpg

sr-window-b.jpg

Problem of SR with a too large window: a packet can be new data or a retransmission (an example with window size = 4):

Window size of SR must be less than or equal to half the size of the sequence number space. ($\leqslant 2^{k-1}$).

可靠数据传输机制及其用途的总结

机制 用途和说明
检验和 用于检测在一个传输分组中的比特错误
定时器 用于超时/重传一个分组,可能因为该分组(或其ACK)在信道中丢失了。由于当一个分组延时但未丢失(过早超时),或当一个分组已被接受方收到但从接收方的ACK丢失时,可能产生超时事件,所以接收方可能会受到一个分组的的多个冗余副本
序号 用于为从发送方流向接收方的数据分组按顺序编号。所接受分组的序号间的空隙可使接收方检测出丢失的分组。具有相同序号的分组可使接收方检测出一个分组的冗余副本
确认 接收方用于告诉发送方一个分组或一组分组已被正确地接收到了。确认报文通常携带着被确认的分组或多个分组的序号。确认可以是逐个的或积累的,这取决于协议
否定确认 接收方用于高速发送方某个分组未被正确地接受。否定确认报文通常携带着未被正确接受的分组的序号
窗口、流水线 发送方也许被限制仅发送那些序号落在一个指定范围的分组。通过允许一次发送多个分组但未被确认,发送方的利用率可在停等操作模式的基础上得到增加。

Connection-Oriented Transport: TCP

The TCP Connection

TCP被称为是面向连接的(connection-oriented),这是因为在一个应用进程可以开始向另一个应用进程发送数据之前,这两个进程必须先相互“握手”,即它们必须相互发送某些预备报文段,以建立确保数据传输的参数。作为TCP连接建立的一部分,连接的双方都将初始化与TCP连接相关的许多TCP状态变量。

这种TCP连接是一条逻辑连接,其共同状态进保留在两个通信端系统的TCP程序中。由于TCP协议只在端系统中运行,而不在中间的网络元素(路由器和链路层交换机)中运行,所以中间的网络元素不会维持TCP连接状态。对于中间路由器来说,它们看不到TCP连接,看到的只是一个个的数据报。

TCP提供的是全双工服务(full-duplex service):如果一台主机上的进程A与另一台主机上的进程B存在一条TCP连接,那么应用层数据就可以从进程B流向进程A的同时,也从进程A流向进程B。TCP连接总是点对点的,即在单个发送方与单个接收方之间的连接。在TCP中不可能出现“多播”的情况,即在一次发送操作中,从一个发送方将数据传送给多个接收方。

TCP连接中发起连接的主机进程被称为客户进程,而另一个进程被称为服务器进程。该客户应用进程首先要通知客户运输层,它想与服务器上的一个进程建立一条连接。建立连接的过程大概如下:客户首先发送一个特殊的TCP报文段,服务器用另一个特殊的TCP报文段来响应,最后,客户再用第三个特殊报文短作为响应。前两个报文段不承载应用层数据,第三个报文段可以承载应用层数据。由于在这两台主机之间发送了三个报文段,因此这种连接建立的过程通常被称为三次握手(three-way handshake)。

一旦建立起一条TCP连接,两个应用进程之间就可以相互发送数据了。客户进程通过套接字传递数据流,数据在进入套接字后就由客户端中运行的TCP程序控制。TCP将这些数据引导到该连接的发送缓存(send buffer)里,发送缓存是发起三次握手期间设置的缓存之一。接下来TCP将不时从发送缓存里取出一块数据,并将数据传递到网络层。如下图所示:

但TCP放入报文段的数据数量不是无限的,这取决于最大报文段长度(Maximum Segment Size,MSS)。MSS通常根据最初确定的由本地发送主机发送的最大链路层帧长度(即所谓的最大传输单元(Maximum Transmission Unit,MTU))来设置。设置该MSS要保证一个TCP报文段加上TCP/IP首部长度(通常40个字节)将适合单个链路层帧。例如以太网和PPP链路层协议都具有1500字节的MTU,因此MSS的典型值为1460字节。

TCP为每块客户数据配上一个TCP首部,从而形成多个TCP报文段(TCP segment)。这些报文段被下传给网络层,网络层将其分别封装在网络层IP数据报中,然后这些IP数据报被发送的网络中。当TCP在另一端接收到一个报文段后,该报文段的数据就被放入该TCP连接的接受缓存中。应用程序从此缓存中读取数据流。该连接的每一端都有各自的发送缓存和接收缓存。

20201215004700137.png

以上可以得出TCP连接的组成包括:一台主机上的缓存、变量和与进程连接的套接字,以及另一台主机上的另一组缓存、变量和与进程连接的套接字。

TCP Segment Structure

TCP报文段由首部字段和一个数据字段组成。数据字段包含一块应用数据。MSS限制了报文段数据字段的最大长度。当TCP发送一个大文件时,TCP通常将该文件划分成长度为MSS的若干块。TCP报文段的结构如下图:

tcp-header.jpg

从上图可以得知,TCP报文段的首部是20字节。与UDP一样,首部包括源端口号和目的端口号,用于多路复用/分解来自或送到上层应用的数据,也包括检验和字段用于校验该分组是否存在比特差错。另外,TCP报文段首部还包含以下字段:

  • 32比特的序号字段和32比特的确认号字段。这些字段被TCP发送方和接收方用来实现可靠数据传输服务,具体后面讨论;
  • 16比特的接收窗口字段。该字段用于指示接收方愿意接受的字节数量,用于流量控制;
  • 4比特的首部长度字段。该字段指示了以32比特的字为单位的TCP首部长度。由于TCP选项字段的原因,TCP首部的长度是可变的。当选项字段为空时,TCP首部的典型长度是20字节;
  • 可选与变长的选项字段。该字段用于发送方与接收方协商最大报文长度(MSS)时,或在高速网络环境下用作窗口调节因子时使用;
  • 6比特的标志字段。ACK比特用于指示确认字段中的值是有效的,即该报文段包括一个对已被成功接收报文段的确认。RST、SYN和FIN比特用于连接建立和拆除。CWR和ECE比特用于明确拥塞通告。当PSH比特被置位时,就指示接收方应立即将数据交给上层,URG比特用来指示报文段里存在着被发送端的上层实体置为“紧急”的数据。紧急数据的最后一个字节由16比特的紧急数据指针字段指出。当紧急数据存在并给出指向紧急数据尾指针的时候,TCP必须通知接收端的上层实体。
序号和确认号

TCP报文段首部中两个最重要的字段是序号字段和确认号字段,这两个字段是TCP可靠传输服务的关键部分。TCP把数据看成一个无结构的、有序的字节流,例如TCP的序号是建立在传送的字节流之上,而不是建立在传送的报文段的序列上。因此在TCP协议中,一个报文段的序号是该报文段首字节的字节流编号。例如,主机A上的一个进程想通过一条TCP连接向主机B上的一个进程发送一个数据流。主机A上的TCP将隐式地对数据流中的每一个字节编号。假定数据流由一个包含50000字节的文件组成,其MSS为100字节,数据流的首字节编号是0。那么该TCP将为该数据流构建500个报文段,第一个报文段的序号是0,第二个报文段的序号是100,第三个报文段的序号是200,以此类推。每一个序号都被填入到相应的TCP报文段首部的序号字段中。

确认号相比序号要难理解一些。之前介绍过,TCP是全双工的,因此主机A在接收来自主机B的数据的同时,也在向主机B发送数据,并且是在同一条TCP连接上。从主机B到达的每个报文段中都有一个序号用于从B流向A的数据。主机A填充进报文段的确认号就是主机A期望从主机B收到的下一字节的序号。例如主机A已经收到了来自主机B的编号为0~311的所有字节,同时它打算发送一个报文段给主机B,由于主机A下一次期望主机B发送过来的首字节是312,因此主机A会在它发往主机B的报文段的确认号字段中填上312。存在另一种情况,主机A接收到了来自主机B的编号为0~311的报文段,以及另一个包含了字节400~500的报文段,并没有收到312~399的报文段。而主机A为了重新构建主机B的数据流,仍在等待字节312~399,因此主机A到主机B的下一个报文段将在确认号中填上312。因为TCP只确认该流中至第一个丢失字节为止的字节,所以TCP被称为提供累计确认 (cummulative acknowledgment)。

当主机在一条TCP连接中收到失序报文段时该怎么办?TCP RFC并没有为此明确规定,而是由TCP的编程人员实现。他有两个基本的选择:①接收方立即丢弃失序报文段;②接收方保留失序的字节,并等待缺少的字节以填补该间隔(后一种选择对网络带宽而言更为有效,是实践中采用的方法)。

值得注意的是,对客户到服务器的数据的确认被装载在一个承载服务器到客户的数据的报文段中;这种确认被称为是被捎带(piggybacked)在服务器到客户的数据报文段中的。

o9D7GZq.png

Round-Trip Time Estimation and Timeout

TCP如同rdt协议一样,它采用超时/重传机制来处理报文段的丢失问题。

  • 超时间隔长度的设置?显然,超时时间间隔必须大于该连接的往返时间(RTT),即从一个报文段发出到它被确认的时间。
  • 如何估计往返时间?
  • 是否应该为所有未确认的报文段各设一个定时器?
估计往返时间

报文段的样本RTT(表示为SampleRTT)就是从某报文段被发出(即交给IP)到对该报文段的确认被收到之间的时间量。大多数TCP的实现仅在某个时刻做一次SampleRTT测量,而不是为每个发送的报文段测量一个SampleRTT.

1
2
3
4
5
6
//指数加权移动平均(Exponential Weighted Moving Average,EWMA)。
//推荐的a=0.25
EstimatedRTT = (1 – a) • EstimatedRTT + a • SampleRTT
//推荐的b=0.25
//DevRTT:RTT偏差,测量RTT的变化。
DevRTT = (1 – b) • DevRTT + b•| SampleRTT – EstimatedRTT |
设置和管理重传超时间隔

超时间隔应该大于等于EstimatedRTT,否则将造成不必要的重传。但超时时间间隔也不能比EstimatedRTT大太多,否则当报文段丢失时,TCP不能很快地重传该报文段,导致数据传输时延大。

1
2
3
//推荐TimeoutInterval值为1秒。超时后,TimeoutInterval值将加倍。
//一旦报文段收到并更新EstimatedRTT后,TimeoutInterval就使用下式
TimeoutInterval = EstimatedRTT + 4 • DevRTT
  • TCP通过使用肯定确认与定时器来提供可靠数据传输。TCP确认正确接收到的数据,而当认为报文段或其确认报文丢失或受损后,TCP会重传这些报文段。

  • TCP使用流水线,使得发送方在任意时刻都可以有多个已发出但还未确认的报文段存在。一个发送方具有的未被确认报文段的确切个数是由TCP的流量控制和拥塞控制机制决定的。

Reliable Data Transfer

对于IP服务,数据报能够溢出路由器缓存而永远不能到达目的地,数据报也可能乱序到达,而且数据报中的比特可能损坏。TCP在IP不可靠的尽力而为服务之上创建一种可靠数据传输服务。TCP的可靠数据传输服务确保了一个进程从其接收缓存中读取数据流是无损坏、无间隔、非冗余和按序的数据流。

接下来讨论:

1)简化版本:发送方只用超时技术来恢复报文段丢失。

2)全面版本:除了使用超时机制外,还使用冗余确认技术。

简化版本描述:TCP发送方有3个与发送和重传有关的主要事件(①从上层应用程序接收数据;②定时器超时;③收到ACK;)

TCP在IP不可靠的尽力而为服务之上创建了一种可靠数据传输服务

  • 发送数据,启动计时器
  • 超时重发,重启计时器
  • 收到ACK,更新确认计数器
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
/* Assume sender is not constrained by TCP flow or congestion control, that data from above is less than MSS in size, and that data transfer is in one direction only. */
NextSeqNum=InitialSeqNumber
SendBase=InitialSeqNumber

loop (forever) {
    switch(event)

        event: data received from application above
            create TCP segment with sequence number NextSeqNum
            if (timer currently not running)
                start timer
            pass segment to IP
            NextSeqNum=NextSeqNum+length(data)
            break;

        event: timer timeout
            retransmit not-yet-acknowledged segment with
                smallest sequence number
            start timer
            break;

        event: ACK received, with ACK field value of y
            if (y > SendBase) {
                SendBase=y
                if (there are currently any not-yet-acknowledged segments)
                    start timer
            }
        break;
} /* end of loop forever */

1)TCP从应用程序接收数据,将数据封装在一个报文段中,并把该报文段交给IP。(①注意到每一个报文段都包含一个序号,这个序号就是该报文段第一个数据字节的字节流编号。②如果定时器还没有为某些其他报文段而运行,则当报文段被传给IP时,TCP就启动该定时器。)

2)超时:TCP通过重传引起超时的报文段来响应超时事件。

3)来自接收方的确认报文段(ACK)的到达:TCP将ACK的值y与它的变量SendBase(是最早未被确认的字节序号)进行比较。TCP采用累积确认,所以y确认了字节编号在y之前的所有字节都已经收到。如果y > SenfBase,则该ACK是在确认一个或多个先前未被确认的报文段。因此,发送方更新它的SendBase变量。

一些有趣的情况

三种丢包重传的情况:(注意图二中只重传第一个没有确认的包,后面的不会重传)

tcp-re-a.jpg

tcp-re-b.jpg

tcp-re-c.jpg

超时间隔加倍

TCP重传具有最小序号的还未确认的报文段。只是每次TCP重传时都会将下一次的超时间隔设为先前值的两倍,而不是用EstimatedRTT和DevRTT推算出的值.

大多数TCP实现中所做的一些修改:TCP重传具有最小序号的还未被确认的报文段。只是每次TCP重传时都会将下一次的超时间隔设为先前值的两倍,而不是从EstimatedRTT和DevRTT推算出的值。然而,每当定时器在另两个事件(即收到上层应用数据或收到ACK)中的任意一个启动,TimeoutInterval由最近的EstimatedRTT和DevRTT推算得到。

优点:这种修改提供了一个形式受限的拥塞控制。定时器过期很有可能是由网络拥塞引起的,即太多的分组到达源与目的地之间路径上一台(或多台)路由器的队列中,造成分组丢失或长时间的排队时延。在拥塞的时候,如果源持续重传分组,会使拥塞更加严重。因此,TCP使用更好的方法,每个发送方的重传都是经过越来越长的时间间隔后进行的。

快速重传

问题:超时触发重传存在的问题是超时周期可能相对较长,当一个报文段丢失时,这种长超时周期迫使发送方延迟重传丢失的分组,因而增加了端到端时延。

解决办法:冗余ACK(duplicate ACK):就是再次确认某个报文段的ACK,而发送方先前已经收到对该报文段的确认。(通过下面理解:发送方通常在超时事件发生之前通过注意所谓冗余ACK来较好地检测到丢包情况。)

因为发送方经常一个接一个地发送大量的报文段,如果一个报文段丢失,就很可能引起许多一个接一个的冗余ACK。如果TCP发送方接收到对相同数据的3个冗余ACK,它把这当做一种暗示,说明跟在这个已被确认3次的报文段之后的报文段已经丢失(为何是3个冗余ACK?)。一旦受到3个冗余ACK,TCP就执行快速重传(fast retransmit),即在该报文段的定时器过期之前重传丢失的报文段。

冗余ACK就是再次确认某个报文段的ACK,而发送方先前已经收到对该报文段的确认 一旦收到三个冗余ACK,TCP就执行快速重传,即在该报文段的定时器过期之前重传丢失的报文段

tcp-fr.jpg

是回退N步还是选择重传

对TCP提出的一种修改意见是所谓的选择确认,它允许TCP接收方有选择地确认失序报文段,而不是累积地确认最后一个正确接受的有序报文段。

TCP是一个GBN协议还是一个SR协议?

1)TCP确认是累积式地、正确地接收,但是失序的报文段是不会被接收方逐个确认的。TCP发送方仅需维持已发送过但未被确认的字节的最小序号(SendBase)和下一个要发送的字节的序号(NextSeqNum)。这个意义下,TCP看起来更像一个GBN风格的协议。

2)但是TCP和GBN协议之间有着一些显著的区别,许多TCP实现会将正确接收但失序的报文段缓存起来。考虑一下当发送方发送一组报文段1、2、…N的序列时,所有的报文段都是在接收方按序无差错的情况下到达的。进一步假设,对包n小于N的确认报文丢失了,但是其余的N-1确认报文在它们各自的超时之前到达了发送端。在这个例子中,GBN不仅会重新传输数据包n,还会传送所有的后续分组,n+1 n+2,…N。另一方面,TCP将重传至多一个报文段,即报文段n。此外,如果报文段n+1的确认报文在报文段n超时之前到达。TCP甚至不会重新传输段n。

3)TCP提出的一种修改意见是所谓的选择确认(selective acknowledgment)[RFC2018],它允许TCP接收方有选择地确认失序报文段,而不是累积地确认最后一个正确接收的有序报文段。当该机制与选择重传机制结合起来使用时(即跳过重传那些已被接收方选择性地确认过的报文段),TCP看起来像SR协议。因此,TCP的差错恢复机制最后被分类为GBN协议与SR协议的混合体。

Flow Control

一条TCP连接的每一侧主机都为该连接设置了接收缓存。当该TCP连接收到正确、按序的字节后,他就将数据放入到接收缓存。(注意:相关联的进程会从该缓存中读取数据,但不是数据刚一到就立即读取。)

TCP为应用程序提供了流量控制服务(flow-control-service)以消除发送方使接收方缓存溢出的可能性。

流量控制服务(flow-control-service):是一个速度匹配服务,即发送方的发送速率与接收方应用程序的读取速率相匹配。

拥塞控制(congestion control):TCP发送方可能因为IP网络的拥塞而被抑制。

注意:本节假设TCP接收方丢弃失序的报文段。

接收窗口(receive window):用于给发送方一个指示:该接收方还有多少可用的缓存空间。TCP通过让发送方维护一个称为接收窗口的变量来控制流量的控制。

因为TCP是全双工通信,在连接两端的发送方都各自维护一个接收窗口。

假设主机A通过一条TCP连接向主机B发送一个大文件。主机B为连接分配了一个接收缓存RecvBuffer表示其大小。

1
2
3
4
5
6
7
//定义以下变量
• LastByteRead: the number of the last byte in the data stream read from the buffer by the application process in B
• LastByteRcvd: the number of the last byte in the data stream that has arrived from the network and has been placed in the receive buffer at B
//由于TCP不允许已分配缓存溢出,下式必须成立:
LastByteRcvd – LastByteRead ≤ RcvBuffer
//接收窗口用rwnd表示,根据缓存可用空间数量来设置:
rwnd = RcvBuffer – [LastByteRcvd – LastByteRead]

由于该空间是随着时间变化的,所以rwnd是动态的,rwnd也称为滑动窗口。

JpD4aJs.png

1)连接是如何使用变量rwnd提供流量控制服务?主机B通过把当前的rwnd值放入它发送给主机A的报文段接收窗口字段中,通知主机A它在该连接的缓存中还有多少可用空间。

开始时,主机B设定rwnd = RecvBuffer。主机A轮流跟踪两个变量LastByteSent和LastByteAcked。(LastByteSent-LastByteAcked:表示主机A发送到连接中但未被确认的数据量)。通过将未确认的数据量控制在rwnd以内,就可以保证主机A不会使主机B的接收缓存溢出。

因此,主机A在整个生命周期需保证:LastByteSent – LastByteAcked ≤ rwnd

2)这个方案有一个小技术问题。 假设主机B的接收缓冲区已满,使得rwnd = 0。在将rwnd = 0通知给主机A,也假设B没有什么可以发送到A。现在考虑发生什么情况,当B中的应用进程清空缓冲区时,TCP不会向主机A发送新的带有rwnd新值的新报文段; 实际上,TCP只有它有数据或者有确认要发送时才会发送保文段向主机A。因此,主机A不知道Host B的接收缓冲区已有新的空间了。即主机A被阻塞,并且不能传输更多的数据! 为了解决这个问题,TCP规范要求:当B的接收窗口为零时,主机A继续发送一个只有1个字节数据的报文段。 这些报文段将会被接收器确认。最终缓冲区将开始清空,并且确认报文里将包含一个非0的rwnd值。

TCP Connection Management

本节关注建立和拆除一条TCP连接。即三次握手,四次挥手。

建立连接

TCP连接的建立会显著地增加人们感受到的时延。客户中的TCP会用以下方式与服务器中的TCP建立一条

TCP连接:

TCP SYN报文段

1)第一步:客户端TCP首先向服务器端的TCP发送一个特殊的TCP报文段(TCP SYN报文段:该报文段不包含应用层数据,但在报文段的首部中的一个标志位SYN被置为1.)。另外,客户会随机选择一个初始序号(client_isn),并将次编号放置与该起始的TCP SYN报文段的序号字段中。该报文段会被封装在一个IP数据报中,并发送给服务器。

SYNACK报文段

2)第二步:一旦包含TCP SYN报文段的IP数据报到达服务器主机(假定它的确达到了),服务器会从该数据报中提取出TCP SYN报文段,为TCP连接分配TCP缓存和变量,并向该客户TCP发送允许连接的报文段(分配的这些缓存和变量,使得TCP易于受到SYN洪泛的拒绝服务攻击),这个允许连接的报文段(SYNACK报文段:该首部有3个重要信息①SYN置为1;②确认号字段被置为client_isn+1;③服务器选择自己的初始序号server_isn,并将其放在TCP报文段首部的序号字段中。)不包含应用层数据。

3)在收到SYNACK报文段后,客户也要给该连接分配缓存和变量。客户主机则向服务器发送另外一个报文段;这最后一个报文段对服务器的允许连接的报文段进行了确认(首部中:①确认字段为server_isn+1;②序号字段为client_isn+1;③SYN比特置为0)。该三次握手的第三个阶段可以在报文段负载中携带客户到服务器的数据。

在以后的每一个报文段中,SYN比特都被置为0;这种连接创建过程被称为3次握手(three-way handshake)。

rX6qD9Y.png

三次握手:

  1. 客户端通过向服务器端发送一个SYN来创建一个主动打开,作为三次握手的一部分。客户端把这段连接的序号设定为随机数 A。
  2. 服务器端应当为一个合法的SYN回送一个SYN/ACK。ACK 的确认码应为 A+1,SYN/ACK 包本身又有一个随机序号 B。
  3. 最后,客户端再发送一个ACK。当服务端受到这个ACK的时候,就完成了三路握手,并进入了连接创建状态。此时包序号被设定为收到的确认号 A+1,而响应则为 B+1。
TCP拆除:

参与一条TCP连接的两个进程中的任意一个都能终止该连接。当连接结束后,主机中的“资源(缓存和变量)”将被释放。

假设某客户打算关闭连接:

1)客户应用进程发送一个关闭连接命令:客户TCP向服务器进程发送一个特许TCP报文段(首部的标志位FIN置为1)。

2)当服务器接收到该报文段后,就向发送方发送一个确认报文段。

3)服务器发送它自己的终止报文段,其FIN比特置为1.

4)客户对这个服务器的终止报文段进行确认。(此时,两个主机用于连接的所有资源都被释放了。)

QY4o3q9.png

客户TCP状态图 1)客户TCP开始处于CLOSED状态。

客户应用程序发起一个新的连接,则客户TCP向服务器中的TCP发送一个SYN报文段。

2)发送过SYN报文段后,客户TCP进入了SYN_SENT状态。

接着,等待来自服务器TCP的对客户所发报文段进行确认且SYN比特被置为1的一个报文段(SYNACK报文段)。

3)收到SYNACK报文段之后,客户TCP进入ESTABLISHED(已建立)状态。

当处在ESTABLISHED状态时,TCP客户就能发送和接收包含有效载荷数据(即应用层产生的数据)的TCP报文段了。

4)假设客户要决定关闭该连接,这引起客户TCP发送一个带有FIN比特被置为1的TCP报文段,进入FIN_WAIT_1状态。

客户等待来自服务器的带有确认的TCP报文段。

5)收到上述报文段后,客户TCP进入FIN_WAIT_2状态。

客户等待来自服务器的FIN比特置为1的另一个报文段。

6)收到上述报文段后,客户TCP对服务器发送确认报文段进行确认,并进入TIME_WAIT状态。

假设ACK丢失,TIME_WAIT状态使TCP客户重传最后的确认报文。在TIME_WAIT状态中所消耗的时间是与具体实现有关的,而典型值是30s,1min,或2min。经过等待后,连接就正式关闭,客户端所有资源(包括端口号)将被释放。

caZ8EU7.png

服务器TCP状态图

w26dgs4.png

下面考虑一台主机接收到一个TCP报文段,其端口号或源IP地址与该主机上进行中的套接字都不匹配。则该主机将向源发送一个特殊重置报文:该报文段将RST标志位置为1.当一台主机接收一个UDP分组,它的目的端口与进行中的UDP套接字不匹配,该主机发送一个特殊的ICMP数据报。

nmap是一个功能强大的工具,该工具不仅能“侦查”打开的TCP端口,也能“侦查”UDP端口,还能侦查防火墙及其配置,甚至能侦查应用程序的版本和操作系统,大多数都能通过操作TCP连接管理报文段完成。可以从http://www.nmap.org中下载nmap。

四次挥手:

注意: 中断连接端可以是客户端,也可以是服务器端. 下面仅以客户端断开连接举例, 反之亦然.

  1. 客户端发送一个数据分段, 其中的 FIN 标记设置为1. 客户端进入 FIN-WAIT 状态. 该状态下客户端只接收数据, 不再发送数据.
  2. 服务器接收到带有 FIN = 1 的数据分段, 发送带有 ACK = 1 的剩余数据分段, 确认收到客户端发来的 FIN 信息.
  3. 服务器等到所有数据传输结束, 向客户端发送一个带有 FIN = 1 的数据分段, 并进入 CLOSE-WAIT 状态, 等待客户端发来带有 ACK = 1 的确认报文.
  4. 客户端收到服务器发来带有 FIN = 1 的报文, 返回 ACK = 1 的报文确认, 为了防止服务器端未收到需要重发, 进入 TIME-WAIT 状态. 服务器接收到报文后关闭连接. 客户端等待 2MSL 后未收到回复, 则认为服务器成功关闭, 客户端关闭连接.

Principles of Congestion Control

在实践中,丢包一般是当网络变得拥塞时由于路由器缓存溢出而引起的。分组重传作为网络拥塞的征兆,但是却无法处理导致网络拥塞的原因。因为有大多的源想以过高的速率发送数据。为了处理网络拥塞,需要一些机制在面临网络拥塞时抑制发送方。

The Causes and the Costs of Congestion

每连接的吞吐量(per-connection throughput):接收方每秒接收的字节数。

1)当分组的到达速率接近链路容量时,分组经历巨大的排队时延。

2)发送方必须执行重传以补偿因为缓存溢出而丢弃的分组。

3)发送方在遇到大时延时所进行的不必要的重传会引起路由器利用链路带宽来转发不必要的分组副本。

4)由于拥塞而丢弃分组的另一种代价:当一个分组沿一条路径被丢弃时,每个上游路由器用于转发分组到丢弃该分组而使用的传输容量最终被浪费掉了。

Approaches to Congestion Control

根据网络层是否为运输层拥塞控制提供显示帮助开划分:

1)端到端拥塞控制:网络层没有为运输层拥塞控制提供显示支持。TCP必须通过端到端的方法解决拥塞控制,因为IP层不会向端系统提供有关网络拥塞的反馈信息。TCP报文段的丢失(通过超时或3次冗余确认而得知)被认为是网络拥塞的一个迹象。

2)网络辅助的拥塞控制:网络层构件(即路由器)向发送方提供有关于网络中拥塞状态的显示反馈信息。这一般有两种形式,如下图:

Network-Assisted Congestion-Control Example: ATM ABR Congestion Control

ATM ABR中的拥塞控制算法,即一种采用网络辅助方法解决拥塞控制的协议。ATM基本上采用一种面向虚电路(VC)的方法来处理分组交换。ABR被设计为一种弹性数据传输服务,该服务方式使人联想起TCP。当网络轻载时,ABR服务会充分利用空闲可用带宽;当网络拥塞时,ABR服务会将其传输速率抑制为某些预先确定的最小传输速率。

TCP Congestion Control

TCP为运行在不同主机上的两个进程之间提供了可靠传输服务和拥塞控制机制。TCP使用端到端拥塞控制(让每一个发送方根据所感受到的网络拥塞程度来限制其能向连接发送流量的速率。)而不是使用网络辅助的拥塞控制,因为IP层不向端系统提供显示的网络拥塞反馈。

本节主要解决3个问题:

1)一个TCP发送方如何限制它向其连接发送流量速率?

2)一个TCP发送方如何感知从它到目的地之间的路径上存在拥塞?

3)当发送方感知到端到端的拥塞时,采用何种算法来改变其发送速率?

TCP连接的每一端包含:①一个接收缓存②一个发送缓存③几个变量(LastByteRead,rwnd等)。另外,运行在发送方的TCP拥塞控制机制跟踪一个额外的变量:拥塞窗口(congestion window,cwmd)。

特别是,在一个发送方中未被确认的数据量不会超过cwmd和rwnd中的最小值。即LastByteSent – LastByteAcked ≤ min{cwnd, rwnd}

TCP发送方如何确定它们的发送速率,即使得网络不会拥塞,于此同时又能充分利用所有可能可用的带宽?

1)一个丢失的报文段意为着拥塞,因此,当丢失报文段时应当降低TCP发送方的速率。

2)一个确认报文段指示该网络正在向接收方交付发送方的报文段,因此,当对先前未确认报文段的确认达到时,能够增加发送方的速率。

3)带宽探测:TCP调节其传输速率的策略是增加其速率以响应达到的ACK,减小其速率以响应丢包事件。

TCP拥塞控制算法(TCP congestion control algorithm):①慢启动;②拥塞控制;③快速恢复。慢启动和拥塞避免是TCP的强制部分,两者的差异在于对收到的ACK做出反应时增加cwnd长度的方式。慢启动比拥塞避免能更快地增加cwnd的长度。快速恢复是推荐部分,对TCP发送方式非必须的。

慢启动

当一条TCP连接开始,cwnd值通常初始置为一个MSS较小值。这使得初始发送速率为MSS/RTT。在慢启动(slow-start)状态,cwnd的值以1个MSS开始并且每当传输的报文段首次被确认就增加一个MSS。

何时结束慢启动阶段的指数增长呢?①如果存在一个由超时指示的丢包事件,TCP发送方将cwnd设置为1并重新开始慢启动过程。它还将第二个状态变量的值ssthresh(慢启动阈值)设置为cwnd/2,即当检测到拥塞时将ssthresh置为拥塞窗口值的一半。②当检测到拥塞时ssthresh设为cwnd的一半,当到达或超过ssthresh的值时,结束慢启动并且TCP转移到拥塞避免模式。③如果检测到3个冗余ACK,这时TCP执行一种快速重传并进入快速恢复状态。

特点:指数增长。

TCP慢启动:

slow-start.jpg

TCP拥塞控制的FSM描述

tcp-congestion-control.jpg

拥塞避免

每个RTT只将cwnd的值增加一个MSS:对于TCP发送方无论何时到达一个新的确认,就将cwnd增加一个MSS(MSS/cwnd)字节。

例如,如果MSS是1460字节,并且cwnd是14 600字节,则在一个RTT内发送10个报文段。每个到达ACK增加1/10MSS的拥塞窗口长度,因此在收到对所有10个报文段的确认后,拥塞窗口的值将增加了一个MSS。

当出现超时时,TCP的拥塞避免与慢启动阶段一样。

当出现丢包时,网络继续从发送方向接收方交付报文段,当接收到3个冗余ACK时,将ssthresh的值置为cwnd的一半,同时将cwnd的值减半加上3个MSS。

快速恢复

1)对收到的每个用冗余ACK,cwnd值增加一个MSS。

2)当对丢失报文段的一个ACK到达时,TCP在降低cwnd进入拥塞避免状态。

3)如果出现超时事件,执行如同慢启动和拥塞避免中相同的动作后,迁移到慢启动状态。

下图延时了Reno版TCP与Tahoe版TCP的拥塞控制窗口的演化情况。

TCP拥塞控制

TCP拥塞控制常被称为加性增、乘性减(Additove-Increase,Multiplicative-Decrease,AIMD)拥塞控制方式:假定丢包由3个冗余的ACK而不是超时指示,TCP的拥塞控制是:每个RTT内cwnd线性增加1MSS,然后出现3个冗余ACK事件时cwnd减半(乘性减)。

TCP吞吐量宏观描述

TCP连接的吞吐量:即平均速率。在一个往返间隔内,TCP发送数据的速率是拥塞窗口(w字节)与当期RTT的函数(TCP发送速率大约是w/RTT)。

一条连接的平均吞吐量 = 0.75*W / RTT

Programming Assignments

Implementing a Reliable Transport Protocol

In this laboratory programming assignment, you will be writing the sending and receiving transport-level code for implementing a simple reliable data transfer protocol. There are two versions of this lab, the alternating-bit-protocol version and the GBN version. This lab should be fun—your implementation will differ very little from what would be required in a real-world situation.

Since you probably don’t have standalone machines (with an OS that you can modify), your code will have to execute in a simulated hardware/software environment. However, the programming interface provided to your routines—the code that would call your entities from above and from below—is very close to what is done in an actual UNIX environment. (Indeed, the software interfaces described in this programming assignment are much more realistic than the infinite loop senders and receivers that many texts describe.) Stopping and starting timers are also simulated, and timer interrupts will cause your timer handling routine to be activated.

Wireshark Lab: Exploring TCP

In this lab, you’ll use your Web browser to access a file from a Web server. As in earlier Wireshark labs, you’ll use Wireshark to capture the packets arriving at your computer. Unlike earlier labs, you’ll also be able to download a Wireshark-readable packet trace from the Web server from which you downloaded the file. In this server trace, you’ll find the packets that were generated by your own access of the Web server. You’ll analyze the client- and server-side traces to explore aspects of TCP. In particular, you’ll evaluate the performance of the TCP connection between your computer and the Web server. You’ll trace TCP’s window behavior, and infer packet loss, retransmission, flow control and congestion control behavior, and estimated roundtrip time.

Wireshark Lab: TCP

Wireshark Lab: Exploring UDP

In this short lab, you’ll do a packet capture and analysis of your favorite application that uses UDP (for example, DNS or a multimedia application such as Skype). As we learned in Section 3.3, UDP is a simple, no-frills transport protocol. In this lab, you’ll investigate the header fields in the UDP segment as well as the checksum calculation.

Wireshark Lab: UDP

Reference

  1. Computer Networking: A Top-Down Approach, 6th Edition
  2. Chapter 3 - Transport Layer
  3. CS144 schedule