一、概述和运输层服务
运输层协议为运行在不同主机上的应用进程之间提供了逻辑通信功能,引用进程使用运输层提供的逻辑通信功能彼此发送报文,而无需考虑承载这些报文的物理基础设施的细节。 如图所示,运输层协议是在端系统中而不是在路由器中实现的。 1:运输层与网络层的关系 网络层提供了主机之间的逻辑通信,而运输层为运行在不同主机上的进程之间提供逻辑通信。
接下来让我们以一个例子类比这个关系,并且这个例子也将贯穿这篇文章的核心。
现在有两个家庭,一家位于黑龙江,一家位于海南。每家都有十二个孩子。黑龙江家庭的孩子们是海南家庭孩子们的堂兄弟姐妹。这两个家庭的孩子们喜欢彼此通信,每个人每星期要互相写一封信,每封信都用单独的信封通过传统的邮政服务传送。因此,每个家庭每星期要向另一家发送144封信。每个家庭都有一个孩子负责收发邮件,黑龙江家庭是建国而海南家庭是阿伟。每星期建国去他所有的兄弟姐妹那里收集信件,并将这些信件交到每天到家门口来的邮政服务车上。当信件到达黑龙江时,建国也负责将信件分发到他的兄弟姐妹手中。同样位于海南的阿伟也负责类似的工作。
由此类比 应用层报文 = 信封上的内容 进程 = 堂兄弟姐妹 主机 = 家庭 运输层协议 = 建国和阿伟 网络层协议 = 邮政服务(包括邮车)
假设某天阿伟或者建国生病了,另外一对堂兄妹阿文和建设来接替他们的工作,但是由于他们年纪太小,没有经验,他们有时候会发错邮件或者丢失邮件。与此类似,计算机网络中也有多种运输协议,每种协议为应用程序提供不同的服务模型。
2:因特网运输层概述 因特网为应用程序提供了两种截然不同的可用运输层协议。一种是UDP(用户数据报协议),它为调用它的应用程序提供了一种不可靠的、无连接的服务。另一种是TCP(传输控制协议),它为调用它的应用程序提供了一种可靠的、面向连接的服务。应用程序的开发人员在生成套接字时必须指定是选择UDP还是TCP。
为简化术语,我们将运输层分组称为报文段(segment),也即将TCP和UDP的分组统称为报文段。
在学习UDP和TCP之前,我们需要先简要了解一下网络层的IP协议,IP的服务模型是尽力而为交付服务这意味着IP尽它最大努力在通信主机之间交付报文段,但它并不做任何确保。特别是,它不确保报文段的交付,不保证报文段的按序交付,不保证报文段中的数据完整性。由于这些原因,IP被称为不可靠服务。在此我们要强调,每台主机至少要有一个网络层地址,即所谓的IP地址。这个“至少”二字的包含的知识就是:每台主机可以有多个IP地址,因为IP地址就是标识这个主机所在的位置,当这个主机连在不同的局域网下,他的IP地址也不尽相同,但是每台主机只能有一个MAC地址。这是每台主机的唯一标识。IP地址可以类比为一个人的收货地址,而MAC地址就是这个人的名字。
了解IP地址后,我们总结一下UDP和TCP所提供服务模型,UDP和TCP最基本的责任是,将两个端系统间IP的交付服务拓展为运行在端系统上的两个进程之间的交付服务。将主机间交付拓展到进程间交付被称为运输层的多路复用(multiplexing)与多路分解(demultiplexing) UDP和TCP还可以通过在其报文段首部中加入差错检查字段而提供完整性检查。进程到进程的数据交付和差错检查时两种最低限度的运输层服务,也是UDP所能提供的仅有的两种服务。而TCP在此基础上还提供可靠数据传输和拥塞控制服务。
二、多路复用和多路分解
在目的主机,运输层从紧邻其下的网络层接收报文段。运输层负责将这些报文段中的数据交付给在主机上运行的适当应用程序进程。 当一个主机上同时有好几个进程时,运输层是怎样区分应该发送那个进程那? 我们知道,一个进程(作为网络应用的一部分)有一个或多个套接字(socket),它相当于从网络向进程传递数据和从进程向网络传递数据的门户。如下图所示,在接收主机中运输层实际上并没有将数据注解交付给进程,而是将数据交给了中间的一个套接字。由于在任一时刻,在接收主机上可能有不止一个套接字,所以每个套接字都有唯一的标识符。 将运输层报文段中的数据交付到正确的套接字的工作称为多路分解。在源主机从不同的套接字中收集数据块,并为每个数据块封装上首部信息从而生成报文段,然后将报文段传递到网络层,所有的这些工作叫做多路复用。
类比: 建国从兄弟姐妹手中收集信件 – 多路复用 建国向兄弟姐妹分发信件 – 多路分解
多路复用的要求:
-
套接字有唯一的标识符;
类比:对于接收方每个孩子都有自己唯一的名字
-
每个报文段有特殊字段来指示该报文段所要交付到的套接字;
类比:对于发送发来说,要在每封信件上写上收信人
源端口号(Source Port) 目的端口号(Destination Port) 当我们在开发一个应用程序时我们必须要为其分配一个端口号。 现在我们应该清楚运输层是怎样实现多路分解的了:在主机上的每个套接字能够分配一个端口号,当报文段送达该主机时,运输层检查报文段的目的端口号,并将其定向到相应的套接字。
1:无连接的多路复用与多路分解 一个UDP套接字是由一个二元组全面标识的,该二元组包含一个目的IP地址和一个目的端口。
因此,如果两个UDP报文段有不同的源IP地址或者是源端口号,但是有相同的目的IP地址和目的端口,那么这两个报文段将通过相同的目的套接字被定向到相同的进程
举个🌰
p3的端口是6428,p2和p1两个不同的进程如果想要给p3发送UDP报文,需要标明自己的源端口号和目的端口号。 那么源端口号的用处是什么呢?主要是用来作为 返回地址,也就是p2可以再向p1 和 p3传送了
2:面向连接的多路复用与多路分解 TCP与UDP的一个细微的差别就是:TCP套接字是由一个四元组(源IP地址,源端口号, 目的IP地址,目的端口号)来标识的。 特别与UDP不同的是,两个具有不同源IP地址或源端口号到达TCP报文段将被定向到两个不同的套接字
举个🌰
主机C作为服务器,主机A向其建立了一个HTTP会话,主机B向其建立了两条HTTP会话,三台主机都是有着自己唯一的IP地址。主机A与主机B的源端口号是相同的,这不是问题,因为B根据IP地址能够分辨。
3:web服务器与TCP 服务器能够根据源IP地址和源端口号来区分来自不同客户的报文段
下面图示是不同的线程建立了TCP连接 4:运输层两个主要协议概述 用户数据报协议 UDP (User Datagram Protocol) 传输控制协议 TCP (Transmission Control Protocol) 两个对等运输实体在通信时传送的数据单位叫作运输协议数据单元 TPDU (Transport Protocol Data Unit)。TCP 传送的数据单位协议是 TCP 报文段(segment),而UDP 传送的数据单位协议是 UDP 报文或用户数据报。
三、无连接运输:UDP
1:UDP概述 UDP(用户数据报协议,User Datagram Protocol),它只是做了运输层协议能够做的最少工作,除了多路复用和多路分解及一些差错检测外,它几乎没有做任何东西。如果应用程序使用的运输层协议是UDP,则应用程序几乎是直接与IP打交道的。
同时,UDP也是一种无连接的运输层协议,因为在使用UDP时,在发送报文段之前,发送方和接收方的运输层实体之间没有进行握手,所谓的握手,就是发送方和接收方通过发送一些特定的报文段来互相确认,从而为发送做准备。
UDP为网络层以上和应用层以下提供了一个简单的接口。UDP只提供数据的不可靠传递,它一旦把应用程序发给网络层的数据发送出去,就不保留数据备份(所以UDP是不可靠的数据报协议),也不要求接收方回复接收成功确认,也不会重发数据,不提供流量控制,更不提供拥塞控制。UDP在IP数据报的头部仅仅加入了复用和数据校验(字段)
主要特点:
- 无连接, 发送数据之前不需要建立连接,因此减少了开销和发送数据之前的时延。
- 使用尽最大努力交付, 即不保证可靠交付,因此主机不需要维持复杂的连接状态表。
- 面向报文, UDP 对应用层交下来的报文,既不合并,也不拆分,而是保留这些报文的边界。UDP 一次交付一个完整的报文。
- 没有拥塞控制, 因此网络出现的拥塞不会使源主机的发送速率降低。这对某些实时应用是很重要的。很适合多媒体通信的要求。
- 支持一对一、一对多、多对一和多对多的交互通信。
- 首部开销小, 只有 8 个字节,比 TCP 的 20 个字节的首部要短。
流行的因特网应用及其下面的运输层协议:
应用 | 医用层协议 | 下面的运输协议 |
---|
电子邮件 | SMTP | TCP | 远程终端访问 | Telnet | TCP | Web | HTTP | TCP | 文件传输 | FTP | TCP | 远程文件服务器 | NFS | 通常UDP | 流式多媒体 | 通常专用 | UDP或TCP | 因特网电话 | 通常专用 | UDP或TCP | 网络管理 | SNMP | 通常UDP | 名字转换 | DNS | 通常UDP |
使用UDP的应用也可以通过增加确认与重传机制来实现可靠数据传输。
2:UDP报文段结构 从下图可以看出,UDP首部只有4个字段,每个字段由两个字节组成,一共8字节大小。
- 源端口号是本机(客户端)的应用程序的套接字所对应的端口号,服务器端可利用此端口号向客户端发送数据。
- 目的端口号是服务端上的应用进程的套接字所对应的端口号,例如HTTP服务器的80端口。
- 长度指明了首部和数据部分的UDP报文段的总长度,单位为字节,即首部+数据。
- 检验和提供了差错检测功能,即检验和用于确定当UDP报文段从源到达目的时,其中的比特是否发生了改变。事实上,计算检验和时,除了UDP报文段以年还使用了IP首部的一些字段。注意,它只能检测到一个报文段发生了错误,但并不能纠正这个错误。
3:UDP检验和 举个🌰 假设我们有 3 个 16 比特的字,分别如下
0110011001100000 0101010101010101 1000111100001100
第一步:对 3 个 16 比特的字依次相加
0110 0110 0110 0000 + 0101 0101 0101 0101 + 1000 1111 0000 1100 = 0100 1010 1100 0010 1
注意,在最后一次加法的过程中,发生了回卷(所谓 “回卷” 就是当进行 16 比特的加法运算的时候,如果进位到 17位,则将第 17 位和后 16 位进行加法和运算),看下面,多了第 17 位,要消除第 17 位 这两个数相加得到
此时用
1 + 0100 1010 1100 0001 = 0100 1010 1100 0010
第二步:对和进行反码运算
0100 1010 1100 0010 的反码 1011 0101 0011 1101
第三步:将这个值放入校验和中 第四步:在接收方中,将全部的 4 个 16比特的字(包含了校验和)加在一起,没有差错的话,就是 1111 1111 1111 1111
4:UDP的优势 1、应用层能更好发控制要发送的数据和发送时间。 为什么采用UDP的应用层能更好地控制发送的数据和时间呢?因为UDP只提供最简单、服务最少的服务,所以当网络应用进程有数据传递给UDP时,UDP马上就会将此数据打包成UDP报文段,并把它交付给网络层,从而把数据发送出去。相反,由于TCP提供了各种的机制,特别是拥塞控制,以便让源和目的主机间的一条或多条链路变得非常拥塞时,遏制运输层TCP发送方,从而让因特网电话、视频会议之类的实时应用性能变得很差。再者,TCP还会继续重发数据报文段直到目的主机收到此报文并加以确认,点面结合 不管可靠的交付需要多少时间。TCP的这些特性,对于一些实时应用来说通常是不适合的,因为它们通常要求以最快的发送速率发送数据,而不想过分地延迟报文的传送,而且它还能容忍一些数据丢失,所以没用必要使用TCP,使用TCP还会增加额外的负担。
2、无需连接建立 如上述的那样,UDP是一个无连接的运输层协议,而TCP在开始数据传输之前要经过三次握手。UDP由于它是一个无连接的协议,所以可以不需要任何准备即可进行数据传输,因此它不会引入建立连接的时延。所以DNS运行在UDP之上而不是TCP之上,因为如果DNS运行在TCP之上,则会由于要建立过多的连接而产生过长连接延时,从而让DNS运行得很慢。
3、无连接状态 TCP由于在提供各种可靠传输的服务,需要在端系统中维护连接状态。此连接状态包括接收和发送缓存、拥塞控制参数、序号与确认序号等参数。而UDP不维护连接状态,也不跟踪这些参数。因此,使用UDP的服务器能支持更多的活动客户机。
4、分组首部开销小 由于UDP提供的服务少,只提供多路分解和多路复用和校验功能,所以其首部字段少,只有8个字节,而TCP的首部有20个字节。
四、可靠数据传输原理
可靠数据传输:为上层实体提供一条可靠的信道进行传输,借助于这条信道,传输数据比特不会受到损坏、丢失,且所以数据都是按其顺序进行交付。 IP网络所提供的是不可靠的传输: 理想的传输条件特点:
- 传输信道不产生差错。
- 不管发送方以多快的速度发送数据,接收方总是来得及处理收到的数据。
在这样的理想传输条件下,不需要采取任何措施就能够实现可靠传输。然而实际的网络都不具备以上两个理想条件,必须使用一些可靠数据传输协议(reliable data transfer protocol),在不可靠的传输信道实现可靠传输。
1:停止等待协议
“停止等待”就是每发送完一个分组就停止发送,等待对方的确认。在收到确认后再发送下一个分组。全双工通信的双方既是发送方也是接收方。 1.无差错情况
2.出现差错 在接收方 B 会出现两种情况:
在这两种情况下,B 都不会发送任何信息,但A都必须重发分组,直到B正确接收为止,这样才能实现可靠通信。
A如何知道 B 是否正确收到了 M1 呢? 解决方法:超时重传 A 为每一个已发送的分组都设置了一个超时计时器。A只要在超时计时器到期之前收到了相应的确认,就撤销该超时计时器,继续发送下一个分组 M2,若A在超时计时器规定时间内没有收到B的确认,就认为分组错误或丢失,就重发该分组。
问题:若分组正确到达B,但B回送的确认丢失或延迟了,A未收到B的确认,会超时重发。B 可能会收到重复的 M1。B如何知道收到了重复的分组,需要丢弃呢? 解决方法:编号 A为每一个发送的分组都进行编号。若B收到了编号相同的分组,则认为收到了重复分组,弃重复的分组,并回送确认。 B为发送的确认也进行编号,指示该确认是对哪一个分组的确认。A根据确认及其编号,可以确定它是对哪一个分组的确认,避免重发发送。若为重复的确认,则将其丢弃。
- 确认丢失和确认迟到
确认丢失: 若 B 所发送的对 M1 的确认丢失了,那么 A 在设定的超时重传时间内不能收到确认,但 A 并无法知道:是自己发送的分组出错、丢失了,或者 是 B 发送的确认丢失了。因此 A 在超时计时器到期后就要重传 M1。 假定 B又收到了重传的分组 M1。这时 B 应采取两个行动: 第一,丢弃这个重复的分组 M1,不向上层交付。 第二,向 A发送确认。不能认为已经发送过确认就不再发送,因为 A 之所以重传 M1 就表示 A 没有收到对 M1 的确认。
确认迟到: 传输过程中没有出现差错,但 B 对分组 M1 的确认迟到了。A 会收到重复的确认。对重复的确认的处理很简单:收下后就丢弃。B 仍然会收到重复的 M1,并且同样要丢弃重复的 M1,并重传确认分组。
2:流水线可靠数据传输协议
当往返时间 RTT 远大于分组发送时间 TD 时,信道的利用率就会非常低。若出现重传,则对传送有用的数据信息来说,信道的利用率就还要降低。 为了提高传输效率,发送方可以不使用低效率的停止等待协议,而是采用流水线传输。 流水线传输:就是发送方可连续发送多个分组,不必每发完一个分组就停顿下来等待对方的确认。这样可使信道上一直有数据不间断地传送。由于信道上一直有数据不间断地传送,这种传输方式可获得很高的信道利用率。 流水线:不以等停方式运行,允许发送方发送多个分组而无需等待确认。但是有以下影响。
- 增加序号范围,每个组一个序号。
- 发送方和接收方需要缓存多个分组。
- 处理丢失、损坏、延迟的数据方法:回退N步(Go Back N,GBN)、和选择重传(Selective Repeat,SR)。
3:回退N步 流水线中未确认的分组数不得超过N过。N被称为窗口长度。GBN协议也叫做滑动窗口协议
- 基序号(base):为最早的未确认分组的序号。
- 下一序号(nextseqnum):为最小的未使用的序号(即下一个待发分组的序号)
如上图所示将序号范围分为4段。在[0,base-1]段内的序号对应于已经发送并被确认的分组。[base,nextseqnum-1]段内的序号对应于已经发送但未被确认的分组。[nextseqnum,base+N-1]段内的序号能用于那些要被立即发送的分组,如果有数据来自上层的话。最后大于或等于base+N的序号是不能使用的,直到当前流水线中未被确认的分组已得到确认为止。
GBN发送方必须响应三种类型的事件:
- 上层的调用:当上层调用rdt_send()时,要检测发送窗口是否已满。如果未满,产生一个分组发送。如果满了,返回数据给上层,然后上层可能过一会儿再试。
- 收到一个ACK。在GBN协议中,对序号为n的分组的确认采取累积确认(cumulative
acknowledgment)的方式,表明接收方已正确收到序号为n的以前且包括n在内的所有分组。 - 超时时间。如果出现超时,发送方重传所有已发送但还未被确认的分组。
GNB接收方则按序接受分组,其他情况则丢弃该分组。
4:选择重传 在GBN中,单个分组的差错能够引起GBN重传大量分组。 选择重传(SR)协议通过让发送方仅重传那些它怀疑在接收方出错的分组而避免不必要的重传。 5:滑动窗口协议 滑动窗口协议比较复杂,是 TCP 协议的精髓所在。发送方维持的发送窗口,它的意义是:位于发送窗口内的分组都可连续发送出去,而不需要等待对方的确认。这样,信道利用率就提高了。连续 ARQ 协议规定,发送方每收到一个确认,就把发送窗口向前滑动一个分组的位置。
- 发送方和接收方分别维持发送窗口和接收窗口,
- 发送方发送后,在收到确认前,发送窗口会变小,
- 接受发接收的分组正确时,向前滑动接收窗口
- 发送方收到确认后,向前滑动发送窗口,窗口变大
6:连续ARQ协议 发送方一次可以发出多个分组。使用滑动窗口协议控制发送方和接收方所能发送和接收的分组的数量和编号,每收到一个确认,发送方就把发送窗口向前滑动。 接收方一般采用累积确认的方式,采用回退N(Go-Back-N)方法进行重传。
累积确认: 接收方一般采用累积确认的方式。即不必对收到的分组逐个发送确认,而是对按序到达的最后一个分组发送确认,这样就表示:到这个分组为止的所有分组都已正确收到了。 优点:容易实现,即使确认丢失也不必重传。 缺点:不能向发送方反映出接收方已经正确收到的所有分组的信息。
连续 ARQ 协议与停止等待协议:
7:可靠传输机制及其用途的总结
机制 | 用途和说明 |
---|
检验和 | 用于检测一个传输分组中的比特错误 | 定时器 | 用于超时/重传一个分组 | 序号 | 用于对从发送方流向接收方的数据分组按顺序编号,可以让接收方检测出丢失或冗余的分组 | 确认 | 接受方用于告诉发送方一个分组或一组分组已被正确地接收到了 | 否定确认 | 接收方告诉发送方某个分组未被正常地接收,通常带着该分组的序号 | 窗口、流水线 | 窗口将发送方发送数据报范围限定在一个范围内的分组,流水线用来增加发送方信道利用率 |
五、面向连接的运输:TCP
TCP是因特网运输层的面向连接的可靠的运输协议。 1:TCP主要特点
- TCP是面向连接的(connection-oriented),这是因为在一个应用进程可以开始向另一个应用进程发送数据之前,这两个进程必须先相互“握手”。即他们必须相互发送某些预备报文段,以建立确保数据传输的参数。
- TCP连接提供的是全双工服务(full-duplex service):即通信双发都可以收发信息。
- TCP连接是点对点(point-to-point)的,即在单个发送方与单个接收方之间的连接。所谓多播,即在一次发送操作中,从一个接收方将数据传送给多个接收方,这种情况对TCP来说是不可能的。
- TCP会将数据引导到该连接的TCP缓存(sender buffer)里,之后就会时不时地从缓存中取一块数据发送。
- TCP可以从发送缓存取出并放入报文段中的数据数量受限于最大报文长度(Maximum Segment Size,MSS)。MSS根据本地主机发送的最大链路层帧长度(即最大传输单元(Maximum Transmission Unit,MTU))设置。
- TCP面向字节流,虽然应用程序和 TCP 的交互是一次一个数据块,但 TCP 把应用程序交下来的数据看成仅仅是一连串无结构的字节流
2:TCP连接 TCP 把连接作为最基本的抽象,每一条 TCP 连接有两个端点。TCP 连接的端点不是主机,不是主机的IP 地址,不是应用进程,也不是运输层的协议端口,其连接的端点叫做套接字 (socket) 或插口。
套接字(socket):由端口号拼接到 (contatenated with) IP 地址构成 例如:套接字 socket = (192.169.1.20 : 2028) 每一条 TCP 连接唯一地被通信两端的两个端点(即两个套接字)所确定。即: TCP 连接就是由协议软件所提供的一种抽象,其连接的端点是个很抽象的套接字,即(IP 地址:端口号)。同一个 IP 地址可以有多个不同的 TCP 连接,同一个端口号也可以出现在多个不同的 TCP 连接中。
Socket 有多种不同的意思:
- 应用编程接口 API 称为 socket API, 简称为 socket。
- socket API 中使用的一个函数名也叫作 socket。
- 调用 socket 函数的端点称为 socket。
- 调用 socket 函数时其返回值称为 socket 描述符,可简称为 socket。
- 在操作系统内核中连网协议的 Berkeley 实现,称为 socket 实现。
3:TCP报文段结构
字段名 | 占位大小 | 作用 |
---|
源端口和目的端口字段 | 各占2字节 | 端口是运输层与应用层的服务接口,运输层的复用和分用功能都要通过端口才能实现。 | 序号字段 | 占 4 字节 | TCP 连接中传送的数据流中的每一个字节都编上一个序号,序号字段的值则指的是本报文段所发送的数据的第一个字节的序号。 | 确认号字段 | 占 4 字节 | 是期望收到对方的下一个报文段的数据的第一个字节的序号 | 数据偏移(即首部长度) | 占 4 位 | 指出 TCP 报文段的数据起始处距离 TCP 报文段的起始处有多远。“数据偏移”的单位是 32 位字(以 4 字节为计算单位) | 保留字段 | 占 6 位 | 保留为今后使用,但目前应置为 0 | 紧急 URG | 占1位 | 当 URG 为 1 时,表明紧急指针字段有效。它告诉系统此报文段中有紧急数据,应尽快传送 | 确认 ACK | 占1位 | 只有当 ACK =1 时确认号字段才有效。当 ACK =0 时,确认号无效 | 推送 PSH | 占1位 | 接收 TCP 收到 PSH = 1 的报文段,就尽快地交付接收应用进程,而不再等到整个缓存都填满了后再向上交付 | 复位 RST | 占1位 | 当 RST=1 时,表明 TCP 连接中出现严重差错(如由于主机崩溃或其他原因),必须释放连接,然后再重新建立运输连接。 | 同步 SYN | 占1位 | 同步 SYN = 1 表示这是一个连接请求或连接接受报文 | 终止 FIN | 占1位 | 用来释放一个连接。FIN=1 表明此报文段的发送端的数据已发送完毕,并要求释放运输连接 | 窗口字段 | 占 2 字节 | 用来让对方设置发送窗口的依据,单位为字节 | 检验和 | 占 2 字节 | 检验和字段检验的范围包括首部和数据这两部分。在计算检验和时,要在 TCP 报文段的前面加上 12 字节的伪首部 | 紧急指针字段 | 占 16 位 | 指出在本报文段中紧急数据共有多少个字节(紧急数据放在本报文段数据的最前面) | 选项字段 | 长度可变 | TCP 最初只规定了一种选项,即最大报文段长度 MSS。MSS 告诉对方 TCP:“我的缓存所能接收的报文段的数据字段的最大长度是 MSS 个字节” | 窗口扩大选项 | 占 3 字节 | 其中有一个字节表示移位值 S。新的窗口值等于 TCP 首部中的窗口位数增大到 (16 + S),相当于把窗口值向左移动 S 位后获得实际的窗口大小。 | 时间戳选项 | 占 10 字节 | 最主要的字段时间戳值字段(4 字节)和时间戳回送回答字段(4 字节) | 选择确认选项 | | | 填充字段 | 不确定长度 | 这是为了使整个首部长度是 4 字节的整数倍 |
MSS (Maximum Segment Size)是 TCP 报文段中的数据字段的最大长度。数据字段加上 TCP 首部才等于整个的 TCP 报文段,所以,MSS是“TCP 报文段长度减去 TCP 首部长度”。
4:往返时间的估计与超时 TCP采用超时/重传机制来处理报文段的丢失问题。因此超时间隔必须大于该连接的往返时间(RTT)。
估计往返时间
-
TCP使用样本估计往返时间。报文段的样本RTT(表示为SampleRTT)就是从某报文段被发出到对该报文段的确认被收到之间的时间量。并且TCP绝不为已重传的报文段计算SampleRTT。 -
TCP维持一个SampleRTT均值(称为EstimatedRTT)来对抗路由器的拥塞和端系统负载的变化。
EstimatedRTT = ( 1 ? α )? EstimatedRTT + α · SampleRTTEstimatedRTT
这种平均通常为称为指数加权移动平均(Exponential Weighted Moving Average,EWMA)。在这里α的建议值为0.125。 -
除了估算RTT,测量RTT的变化也是有价值的,RTT变差DecRTT如下,β 的推荐值为0.25。
DevRTT = ( 1 ? β )? DevRTT + β ? ∣ SampleRTT ? EstimatedRTT ∣
设置和管理超时重传超时间隔
TimeoutInterval = EstimatedRTT + 4 ? DevRTT
5:可靠数据传输
-
TCP在IP不可靠的尽力而为的服务之上创建了一种可靠数据传输服务(reliable data transfer service)。确保一个进程从其接受缓存中读出的数据流是无损坏、无间隔、非冗余、按序的数据流。即该字节流与连接的另一方端系统发送出的字节流是完全相同的。 -
TCP有三个与发送和重传有关的重要事件:
- 从上层应用程序接收数据:一旦接收到数据,TCP将数据封装到一个报文中,并交给IP。
- 超时:TCP通过重传引起超时的报文来相应超时时间,并重启定时器。
- 收到ACK:TCP会将收到的ACK与它的SendBase(最早未被确认的字节序号)进行比较,并作出相应的动作。
-
TCP每次重传都会将下一次的超时间隔TimeoutInterval设置为之前的两倍,而不是之前有均值和偏差所求的公式. -
TCP使用冗余ACK(duplicate ACK)就是再次确认某个报文段的ACK,而发送方先前已经收到对该报文段的确认,但是后续的数据可能丢失,因此要再次发送。 -
TCP的差错恢复机制是回退N步GBN和选择重传SR的混合体。
5.1以字节为单位的滑动窗口 TCP 使用流水线传输和滑动窗口协议实现高效、可靠的传输,TCP 的滑动窗口是以字节为单位的。 发送方 A 和接收方 B 分别维持一个发送窗口和一个接收窗口。发送窗口表示:在没有收到确认的情况下,可以连续把窗口内的数据全部发送出去。接收窗口表示:只允许接收落入窗口内的数据。 根据 B 给出的窗口值,A 构造出自己的发送窗口。 发送窗口表示:在没有收到 B 的确认的情况下,A 可以连续把窗口内的数据都发送出去。 发送窗口里面的序号表示允许发送的序号。 显然,窗口越大,发送方就可以在收到对方确认之前连续发送更多的数据,因而可能获得更高的传输效率。 发送缓存: 接收缓存: 发送缓存与接收缓存的作用:
- 发送缓存用来暂时存放发送应用程序传送给发送方 TCP 准备发送的数据和TCP 已发送出但尚未收到确认的数据。
- 接收缓存用来暂时存放:按序到达的、但尚未被接收应用程序读取的数据和不按序到达的数据。
5.2超时重传时间选择 重传机制是 TCP 中最重要和最复杂的问题之一。TCP 每发送一个报文段,就对这个报文段设置一次计时器,只要计时器设置的重传时间到但还没有收到确认,就要重传这一报文段。重传时间的选择是 TCP 最复杂的问题之一。 往返时延的方差很大: TCP 超时重传时间设置:
- 如果把超时重传时间设置得太短,就会引起很多报文段的不必要的重传,使网络负荷增大。
- 但若把超时重传时间设置得过长,则又使网络的空闲时间增大,降低了传输效率。
- TCP 采用了一种自适应算法,它记录一个报文段发出的时间,以及收到相应的确认的时间。这两个时间之差就是报文段的往返时间 RTT。
加权平均往返时间: TCP保留了RTT的一个加权平均往返时间RTTS(这又称为平滑的往返时间)。 第一次测量到 RTT 样本时,RTTS值就取为所测量到的 RTT 样本值。以后每测量到一个新的 RTT 样本,就按下式重新计算一次 RTTS: 式中,0 ≤α ≤ 1。若 α 很接近于零,表示 RTT 值更新较慢。若选择 ? 接近于 1,则表示 RTT 值更新较快。 RFC 6298 推荐的 α 值为 1/8,即 0.125。
超时重传时间RTO RTO (Retransmission Time-Out) 应略大于上面得出的加权平均往返时间 RTTS。 RFC6298 建议使用下式计算 RTO: RTTD 是 RTT 的偏差的加权平均值。 RFC 6298 建议这样计算RTTD 。第一次测量时, RTTD 值取为测量到的 RTT 样本值的一半。在以后的测量中,则使用下式计算加权平均的 RTTD : β是个小于 1 的系数,其推荐值是 1/4,即 0.25。
往返时间 (RTT) 的测量相当复杂 TCP 报文段 1 没有收到确认。重传(即报文段 2)后,收到了确认报文段 ACK。 如何判定此确认报文段是对原来的报文段 1 的确认,还是对重传的报文段 2 的确认?
Karn 算法: 在计算平均往返时间 RTT 时,只要报文段重传了,就不采用其往返时间样本。这样得出的加权平均平均往返时间 RTTS和超时重传时间 RTO就较准确。但是,这又引起新的问题。当报文段的时延突然增大了很多时,在原来得出的重传时间内,不会收到确认报文段。于是就重传报文段。但根据Karn 算法,不考虑重传的报文段的往返时间样本。这样,超时重传时间就无法更新。 修正的 Karn 算法: 报文段每重传一次,就把 RTO增大一些: 系数 γ 的典型值是 2 。当不再发生报文段的重传时,才根据报文段的往返时延更新平均往返时延 RTT 和超时重传时间 RTO的数值。实践证明,这种策略较为合理。
5.3选择确认ACK 问题:若收到的报文段无差错,只是未按序号,中间还缺少一些序号的数据,那么能否设法只传送缺少的数据而不重传已经正确到达接收方的数据?答案是可以的。选择确认 SACK (Selective ACK) 就是一种可行的处理方法。
接收到的字节流序号不连续 TCP 的接收方在接收对方发送过来的数据字节流的序号不连续,结果就形成了一些不连续的字节块。
6:流量控制
- 由于接收方并不一定马上从TCP缓存读取数据,而接收方如果一直发数据,会造成接收缓存溢出。
- TCP为它的应用程序提供了流量控制服务(flow-control service)以消除缓存溢出的可能性。
- TCP通过让发送方维护一个称为接收窗口(congestion control)的变量来提供流量控制,指明接收方还有多少可用的缓存空间。由于TCP是全双工通信的,连接双方的都各自维护一个接收窗口。
- 当接收窗口值为0时,发送方仍会发送一个只有一字节的报文段,最终会被接收方确认,最终缓存将开始清空,并且返回一个非0的接收窗口值。
利用可变窗口进行流量控制举例 A 向 B 发送数据。在连接建立时,B 告诉 A:“我的接收窗口 rwnd = 400(字节)”。 在这里插入图片描述 可能发生死锁 : B 向 A 发送了零窗口的报文段后不久,B 的接收缓存又有了一些存储空间。于是 B 向 A 发送了 rwnd = 400的报文段。 但这个报文段在传送过程中丢失了。A 一直等待收到 B 发送的非零窗口的通知,而 B 也一直等待 A 发送的数据。 如果没有其他措施,这种互相等待的死锁局面将一直延续下去。 为了解决这个问题, TCP 为每一个连接设有一个持续计时器(persistence timer) 。 只要 TCP 连接的一方收到对方的零窗口通知,就启动该持续计时器。 若持续计时器设置的时间到期,就发送一个零窗口探测报文段(仅携带 1 字节的数据),而对方就在确认这个探测报文段时给出了现在的窗口值。 若窗口仍然是零,则收到这个报文段的一方就重新设置持续计时器。 若窗口不是零,则死锁的僵局就可以打破了。
7:TCP连接管理
三次握手 TCP 建立连接的过程叫做握手。握手需要在客户和服务器之间交换三个 TCP 报文段,称之为三次握手。采用三报文握手主要是为了防止已失效的连接请求报文段突然又传送到了,因而产生错误。
- 上图中主机B的 TCP 服务器进程先创建传输控制块TCB,准备接受客户进程的连接请求。
- 主机A 的 TCP 向 主机B 发出连接请求报文段,其首部中的同步位 SYN = 1,并选择序号 seq = x,表明传送数据时的第一个数据字节的序号是 x。
- 主机B 的 TCP 收到连接请求报文段后,如同意,则发回确认。主机B 在确认报文段中应使 SYN = 1,使 ACK = 1,其确认号ack = x + 1,自己选择的序号 seq = y。
- 主机A 收到此报文段后向 主机B 给出确认,其 ACK = 1,确认号 ack = y + 1。主机A 的 TCP通知上层应用进程,连接已经建立。
- 主机B 的 TCP 收到主机 A 的确认后,也通知其上层应用进程:TCP 连接已经建立。
总结三次握手的目的就是确保通信双方都处于连接状态,并且知道对方是连接状态。
天下无不散的宴席,对于TCP连接也是如此。参与一条TCP连接的两个进程中的任何一个都能终止该连接。当连接结束后,主机中的“资源”将被释放。
四次挥手 TCP 连接释放过程比较复杂。数据传输结束后,通信的双方都可释放连接,TCP 连接释放过程是四次挥手。
- 数据传输结束后,通信的双方都可释放连接。现在 主机A 的应用进程先向其 TCP 发出连接释放报文段,并停止再发送数据,主动关闭 TCP连接。主机A 把连接释放报文段首部的FIN = 1,其序号seq = u,等待 B 的确认。
- 主机B 发出确认,确认号 ack = u+1,而这个报文段自己的序号 seq = v。TCP 服务器进程通知高层应用进程。从 主机A 到主机B 这个方向的连接就释放了,TCP 连接处于半关闭状态。主机B 若发送数据,主机A 仍要接收。
- 若 主机B 已经没有要向 主机A 发送的数据,其应用进程就通知 TCP 释放连接。
- 主机A 收到连接释放报文段后,必须发出确认。 在确认报文段中ACK = 1,确认号 ack = w + 1,自己的序号 seq = u +1。
总结四次挥手的目的是确保双方都已经断开连接并且各自缓存中的数据都发送完毕。
主机A必须等待 2MSL 的时间:
第一,为了保证 主机A 发送的最后一个 ACK 报文段能够到达 主机B 第二,防止 “已失效的连接请求报文段”出现在本连接中
保活计时器: 用来防止在TCP连接出现长时期的空闲。保活计时器 通常设置为2小时 。若服务器过了2小时还没有收到客户的信息,它就发送探测报文段。若发送了10个探测报文段(每一个相隔75秒)还没有响应,就假定客户出了故障,因而就终止该连接。
六、拥塞控制原理
1:拥塞控制的一般原理 在某段时间,若对网络中某资源的需求超过了该资源所能提供的可用部分,网络的性能就要变坏。这种现象称为拥塞 (congestion)。最坏结果:系统崩溃。 拥塞控制与流量控制的区别:
2:拥塞原因与代价
- 排队时延:即当分组的到达速率接近链路容量时,分组经历巨大的排队时延。
- 丢包重传:即发送方在遇到大时延时所进行的不必要重传会引起路由器利用其链路带宽来转发不必要的分组副本。
- 冗余分组:即当一个分组沿一条路径被丢弃时,每个上游路由器用于转发该分组到丢弃该分组而使用的传输容量最终被浪费掉了。
3:拥塞控制方法
-
端到端拥塞控制 :即使网络中存在拥塞,端系统也必须通过对网络行为的观察(如分组丢失与时延)来推断网络是否存在拥塞。网络层没有为运输层拥塞控制提供显示支持。 -
网络辅助的拥塞控制:网络层构件(即路由器)向发送方提供关于网络中拥塞状态的显示反馈信息。这种反馈可以简单的用一个比特来表示。 网络辅助的拥塞控制又分为两种 1.由网络路由器发给发送方。 2.路由器标记或更新从发送方流向接收方的分组中的某个字段来指示拥塞的产生。
七、TCP拥塞控制
我们已经知道TCP为运行在不同主机上的两个进程之间提供了可靠传输服务。TCP的另一个关键部分就是拥塞控制机制。TCP必须使用端到端拥塞控制而不是使用网络辅助的拥塞控制,因为IP层不向端系统提供显式的网络拥塞服务。
TCP所采用的方法是让每个发送方根据所感知到的网络拥塞程度来限制其能向连接发送流量的速率。如果一个TCP发送方感知从它到目的地之间的路径上没有什么拥塞,则TCP发送方增加其发送速率;如果发送方感知沿着该路径有拥塞,则发送方就会降低其发送速率。但是这种方法提出了三个问题: 【问题1】一个TCP发送方如何限制它向其连接发送流量的速率?
- 通过调节拥塞窗口cwnd的值。(cwnd是拥塞窗口(congestion window)是接收方TCP缓存剩余的空间,rwnd是滑动窗口,是发送方发送数据用于回退N步和选择重传的那个窗口。)
【问题2】 一个TCP发送方如何感知网络中存在拥塞?
- 将 “丢包事件“ 定义为要么出现超时,要么收到三个冗余的ACK。
- 出现丢包事件,发送方就认为路径上出现了拥塞的指示。
【问题3】 当发送方感知到端到端的拥塞时,用何种算法改变其发送速率呢?
- TCP拥塞控制算法(TCP congestion control algorithm)
TCP拥塞控制算法包括以下三个部分。其中慢启动和拥塞避免的差异在增加cwnd的长度上。快速回复是推荐部分。并维护一个阈值threshold,当窗口小于阈值时使用慢启动,大于阈值时使用拥塞避免。 (1)慢开始
慢开始 (Slow start) 目的:用来确定网络的负载能力或拥塞程度。 算法的思路:由小到大逐渐增大拥塞窗口数值。 两个变量:
拥塞窗口 cwnd 控制方法:在每收到一个对新的报文段的确认后,可以把拥塞窗口增加最多一个 SMSS 的数值。
其中 N 是原先未被确认的、但现在被刚收到的确认报文段所确认的字节数。 不难看出,当 N < SMSS 时,拥塞窗口每次的增加量要小于SMSS。 用这样的方法逐步增大发送方的拥塞窗口 cwnd,可以使分组注入到网络的速率更加合理。
发送方每收到一个对新报文段的确认(重传的不算在内)就使 cwnd 加 1。
每经过一个传输轮次,拥塞窗口就加倍。窗口大小按指数增加,不慢!
传输轮次 使用慢开始算法后,每经过一个传输轮次 (transmission round),拥塞窗口 cwnd 就加倍。 一个传输轮次所经历的时间其实就是往返时间 RTT。 设置慢开始门限状态变量 ssthresh, 慢开始门限 ssthresh 的用法如下:
- 当 cwnd < ssthresh 时,使用慢开始算法。
- 当 cwnd > ssthresh 时,停止使用慢开始算法而改用拥塞避免算法。
- 当 cwnd = ssthresh 时,既可使用慢开始算法,也可使用拥塞避免算法。
(2)拥塞避免
拥塞避免算法(congestion avoidance) 思路: 让拥塞窗口 cwnd 缓慢地增大,避免出现拥塞。 每经过一个传输轮次,拥塞窗口 cwnd = cwnd + 1。 使拥塞窗口 cwnd 按线性规律缓慢增长。 在拥塞避免阶段,具有“加法增大” (Additive Increase) 的特点。 在超时之前,每经过一个传输轮次就使 cwnd 加 1。
当网络出现拥塞时: 无论在慢开始阶段还是在拥塞避免阶段,只要发送方判断网络出现拥塞(重传定时器超时): ssthresh = max(cwnd/2,2) cwnd = 1 执行慢开始算法 目的:迅速减少主机发送到网络中的分组数,使得发生拥塞的路由器有足够时间把队列中积压的分组处理完毕。
(3)快重传
快重传 (fast retransmit) 发送方只要一连收到三个重复确认,就知道接收方确实没有收到报文段,因而应当立即进行重传(即“快重传”),这样就不会出现超时,发送方也不就会误认为出现了网络拥塞。 使用快重传可以使整个网络的吞吐量提高约20%。 不难看出,快重传并非取消重传计时器,而是在某些情况下可以更早地(更快地)重传丢失的报文段。 采用快重传 FR (Fast Retransmission) 算法可以让发送方尽早知道发生了个别报文段的丢失。 快重传算法首先要求接收方不要等待自己发送数据时才进行捎带确认,而是要立即发送确认,即使收到了失序的报文段也要立即发出对已收到的报文段的重复确认。
(4)快恢复
快恢复 (fast recovery) 当发送端收到连续三个重复的确认时,由于发送方现在认为网络很可能没有发生拥塞,因此现在不执行慢开始算法,而是执行快恢复算法 FR (Fast Recovery) 算法: 慢开始门限 ssthresh = 当前拥塞窗口 cwnd / 2 ; 新拥塞窗口 cwnd = 慢开始门限ssthresh ; 开始执行拥塞避免算法,使拥塞窗口缓慢地线性增大。
慢开始和拥塞避免算法的实现举例: 因此,在图的点4,发送方知道现在只是丢失了个别的报文段。于是不启动慢开始,而是执行快恢复算法。这时,发送方调整门限值 ssthresh = cwnd / 2 = 8,同时设置拥塞窗口 cwnd = ssthresh = 8(见图中的点5),并开始执行拥塞避免算法。 加法增大,乘法减小 (AIMD) 可以看出,在拥塞避免阶段,拥塞窗口是按照线性规律增大的。这常称为“加法增大” AI (Additive Increase)。 当出现超时或3个重复的确认时,就要把门限值设置为当前拥塞窗口值的一半,并大大减小拥塞窗口的数值。这常称为“乘法减小”MD (Multiplicative Decrease),二者合在一起就是所谓的 AIMD 算法。 TCP拥塞控制流程图 发送方的发送窗口的上限值应当取为接收方窗口 rwnd 和拥塞窗口 cwnd 这两个变量中较小的一个,即应按以下公式确定:
- 当 rwnd < cwnd 时,是接收方的接收能力限制发送窗口的最大值。
- 当 cwnd < rwnd 时,则是网络的拥塞限制发送窗口的最大值。
- 也就是说,rwnd 和 cwnd 中数值较小的一个,控制了发送方发送数据的速率。
八、TCP的有限状态机
箭头旁边的字,表明引起这种变迁的原因,或表明发生状态变迁后又出现什么动作,图中有三种不同的箭头。
- 粗实线箭头表示对客户进程的正常变迁。
- 粗虚线箭头表示对服务器进程的正常变迁。
- 细线箭头表示异常变迁。
|