第三章 运输层
运输层位于应用层和网络层之间,该层为运行在不同主机发应用进程提供直接的通信服务起着至关重要作用。我们要特别关注TCP和UDP这些因特网协议。
3.1运输层服务
运输层协议为运行在不同主机上的应用进程提供逻辑通信。应用进程使用运输层提供的逻辑通信功能彼此发送报文,而无需考虑承载这些报文的物理设施的细节。
运输层协议是在端系统而不是在路由器中实现的。在发送端,运输层将从发送应用程序进程接收到的报文转换成运输层分组,这个分组叫做运输层报文段,可能是将应用报文划分为较小的快,每块加上一个运输层首部以生成运输层报文段。
然后在发送端系统中,运输层将这些报文段传输到网络层,网络层将其封装成网络层分组(即数据报)并向目的端发送;在接收端中,网络层数据包中提取运输层报文段,并将该报文段上交给运输层;运输层则处理接收到的报文段,使该报文段中的数据为接受应用程序使用。
其中网络路由器只作用于该数据报的网络层字段,不检查封装在该数据报运输层报文段的字段。
运输层与网络层关系
举个栗子。
有两个家庭,每个家庭有多个孩子,他们经常互相写信。在A家庭中有一个孩子a1每天负责将大家的信件统一收起来交到邮车上面,同样B家庭的b1也在做同样的事情。
在栗子中邮政为两个家庭之间提供逻辑通信(是将信件从一家送到一家而不是一个人到另一个人);另一方面a1和b1为兄弟姐妹之间提供了逻辑通信,从兄弟姐妹角度看a1和b1就是邮件服务,尽管他们只是端到端交付过程中的一部分(即端系统部分)。
类比 | |
---|---|
应用层报文 | 信封上的字符 |
进程 | 兄弟姐妹 |
主机(端系统) | 家庭 |
运输层协议 | a1和b1 |
网络层协议 | 邮政 |
运输层协议只工作在端系统中,将来自应用进程的报文移动到网络边缘。但运输服务能够提供的服务常常受制于网络层协议的服务模型。但是即使底层网络协议是不可靠的,运输协议也可以提供可靠数据传输。
3.2多路分解和多路复用
一个进程有一个或多个套接字(socket),相当于从网络向进程传递数据和从进程向网络传递数据的门户。所以在接受主机的运输层实际上并没有直接将数据交付给进程,而是将数据交给了中间的一个套接字(因为套接字可能有多个,所以每个套接字都有唯一的标识符,标识符的格式取决于它是UDP还是TCP套接字)。
-
多路分解:分解发生在接收端,利用传输层头部信息将接受到的报文段投递给正确的套接字。
-
多路复用:复用发生在发送端,在源主机从不同套接字中收集数据块,并为每个数据块封装上首部信息(为了以后分解)从而生成报文段,然后将报文段传递到网络层。
多路复用要求:
-
套接字有唯一标识符。
-
每个报文段有特殊字符来指示该报文段交付到的套接字。
这些特殊字段是源端口号字段和目的端口号字段,端口号是一个16比特的数,大小在0~65535之间,0-1023范围的端口号成为周知端口号,是受限制的(这是指它们保留给HTTP,FTP之类的周知应用层协议来使用)
无连接的多路复用和多路分解
需要注意的是,在创建Socket的时候,是由运输层为之分配端口号;一个UDP套接字是由一个目的IP地址和目的端口号即二元组来标志的;如果两个UDP报文段有不同的源IP地址或者源端口号,但是有相同的目的IP和目的端口号的话,它们将通过同一个Socket到达同一个应用程序。
UDP 的多路分解 均指向同一端口的Socket,但是数据来自不同IP。
源端口是在接收方回传信息给发送方时候目的端口号就是这里的源端口号。
关于报文段格式:
多路复用与多路分解;UDP报文段格式;套接字和端口号_Unique-You的博客-CSDN博客_udp多路分解
面向连接的多路复用和多路分解
TCP协议中的Socket是通过一个四元组来标记的:(源IP地址,源端口号,目的IP地址,目的端口号);
两个具有不同源IP地址或者源端口号,但有相同的目的IP地址和目的端口号的TCP报文段将通过两个不同的Socket进入同一应用进程(除非TCP报文段携带了初始创建连接的请求);这也表示,一个应用进程可以关联多个Socket,而一个Socket将只关联一个应用进程;常常,这样的对应关系是通过线程来实现的:一个进程有多个线程,而每个线程关联了一个Socket;这样做可以提高服务器性能。
实际上,传输层就是根据这些信息来实现多路分解的;而这些信息是在多路复用的时候被放置在报文段中的。
3.3无连接运输:UDP
不提供不必要服务的最简化运输层协议最低限度要提供一种分解和复用服务,而不是上面都不做。而UDP除了复用/分解和少量的差错检测之外,几乎没有对IP增加别的东西。
UDP从应用进程得到数据,附加上用于多路分级和多路复用的源和目的端口号字段,以及两个其他的小字段,然后将新合成的报文段交给网络层,网络层将运输层报文段封装到一个IP数据报中,尽全力交付给主机。在运送艾伯文端之前,发送方和接受方的运输层实体之间是没有握手的,所以称为无连接的。
选用UDP优势:
-
使用UDP协议中只要UDP接收到数据就会立刻形成一个报文段并传递到网络层。而TCP具有网络拥塞控制,在链路中出现拥塞的情况下会遏制发送方的传送速率。同样TCP需要接收方加以确认却不保证这一过程(可靠交付)需要多少时间。对于实时应用来说,通常要求最小的发送速率,不希望过分的延迟报文段的传送,且能容忍一部分数据丢失。
-
无须建立连接。TCP开始传送速率之前需要三次握手,UDP却不需要任何准备直接传输,因此UDP不会引入建立连接的时延。
-
无连接。TCP需要在短息通知端系统之间维护连接状态(包括接送和发送缓存,拥塞控制参数以及序号与确认号的参数,因为在可靠数据传输和拥塞控制中这是必须的)。而UDP不需要维护连接状态和跟踪参数。因此,某些专门用于某种特定应用的服务器当应用进程运行在UDP之上而不是运行在TCP上时,一般都能支持更多的活跃用户。
-
首部开销小。每个TCP报文段都有20个字节的首部开销,而UDP只有8字节。
判断使用的是TCP还是UDP
对于需要数据不可以丢失的情况(例如电子邮件,文本传输)都需要TCP的可靠数据传输;对于网络处于重压状态下的情况(例如UDP用于承载网络管理数据SNMP),TCP的拥塞控制传输难以实现。
而对于多媒体应用(如视频,电话,流式存储视频和音频),这种药拒绝延时,需要实时传输。(但是需要注意的是这样也会哟潜在的风险,书132页),因此在UDP中也可以实现可靠通信
常见的因特网应用及其下面的运输协议
应用 | 应用层协议 | 下面的传输协议 |
---|---|---|
电子邮件 | SMTP | TCP |
远程终端访问 | Telnet | TCP |
Web | HTTP | TCP |
文件传输 | FTP | TCP |
远程文件服务器 | NFS | 通常UDP |
流式多媒体 | 通常专用 | UDP和TCP |
因特网电话 | 通常专用 | UDP和TCP |
网络管理 | SNMP | 通常UDP |
名字转换 | DNS | 通常UDP |
UDP报文结构
UDP首部只有4个字段,每个字段由两个字节组成(所以首部只有8给字节),长度字段指示了报文段中的字节数(首部加数据)
UDP检验和
UDP检验和提供过了差错检测的功能,检验和用于确定当UDP报文段从源到达目的地移动的时候其中的比特是否发生了变化。UDP对所有的16比特字的和进行反码运算,求和时任何任何溢出都会被回卷。
例:
有三个16位比特字:0110011001100000
0101010101010101
1000111100001100
前两个相加为 1011101110110101
再加上第三个为 10100101011000001
有溢出了,将最高位回卷,得到
0100101011000010
在接收方,4个16位比特字,包括检验和加在一起如果没有错误,就应该是1111111111111111,如果有0,就说明出错了。但是UDP对于差错恢复没有能力
3.4可靠数据传输
可靠数据传输为上层实体提供的服务抽象是:数据可以通过一套可靠的信道进行传输,借助于可靠信道,传输数据就不会受到损坏或者丢失;并且所有数据都可以按照其发送顺序进行交付。而这正是TCP向调用它的应用所提供的服务模型
实现这种抽象服务是可靠数据传输的责任,但是因为可靠数据传输的底层协议可能是不可靠的,所以这项任务有一点困难;
单方向的可靠数据传输流程大概是这样的:可靠数据传输->不可靠数据传输->不可靠的传输信道->可靠数据接收->上传Data
我们仅考虑单向数据传输,但是控制信息是双向流动的。
我们以有限状态机(FSM)定义发送方和接收方
经完全可靠信道的可靠数据传输:rdt1.0
在最简单的情况中,底层信道完全可靠,发送方接受来自叫高层的数据,产生一个包含该数据的分组,并将分组发送到信道上;接收方从底层信道接收一个分组,从分组中提取数据并将数据传给较高层。
所有的分组都是从发送方流向接收方,接收方无需提供任何反馈信息给发送方,接收方接收和发送方发送速率一样。
经具有比特差错信道的可靠数据传输:rdt2.0
在这个情况中,比特可能受损。
自动重传请求(ABQ协议)
-
差错检测:需要一种机制使接受方检测到合适出现了比特差错,要求有额外的比特从发送放到接收方,这些比特将被汇集在数据分组的分组检验和字段中。
-
接收方反馈:接收方需要回传ACK(肯定确认)和NAK(否定确认)让发送方了解分组是否被正确接收。
-
重传:接收方收到差错分组,发送方重传
rdt2.0的发送端每发送一个分组需要等待接收端的确认信号,这种协议被称为停等协议。
rdt2.1
考虑到了ACK和NAK分组受损的情况
考虑ACK和NAK受损的两个可能性:
-
增加足够的校验和比特
-
当接受到模糊不清的ACK和NAK分组时,只需要重传当前数据分组。这引入了冗余分组,但是冗余分组的根本困难是接收方不知道它回传的ACK或者NAK是否被发送方收到,因此不知道这次接收到的分组是新的分组还是重传的分组
解决方法:引入序号
发送方对数据分组进行编号,接收方只需要检查序号就可以知道接收到的分组是否是一次重传,NAK和ACK没有序号(因为信道中没有出现丢失分组的情况)
rdt2.2:无NAK的协议
如果不发送NAK,而是对上次正确接收的分组发送一个ACK,我们也能实现同样的效果。
发送方接收到对一个分组的两个ACK(冗余ACK)后,就知道接收方没有正确接收到跟在确认两次的分组后面的分组。
rdt 2.2 是在有比特差错信道上实现的一个无NAK的可靠数据传输协议。
rdt 2.1和rdt 2.2的区别在于,接收方此时必须包括由一个ACK报文所确认的分组序号
rdt3.0:经具有比特差错的丢包信道的可靠数据传输
在比特受损的前提下,底层信道还会出现丢包现象,rdt3.0中,丢包问题由发送方来解决。无论是分组丢失还是接收方回传的ACK丢失,只要在一定时间内没有收到ACK,就重传这个分组(即使没有出现丢失情况,但是超时了也会重传)。
由此产生的 冗余数据分组 则由接收方通过序号处理。为了实现基于时间的重传机制,需要一个倒计时定时器
因为分组序号在 0 和 1 之间交替,因此 rdt 3.0 有时被称为 比特交替协议。
流水线可靠数据传输协议
rdt问题:发送方利用率太低
两个端系统之间的光速往返传播时延为RTT,发送速率为R,包括首部字段和数据的分组长L,
发送方大部分时间都在闲着,所以不以停等的方式运行,允许发送方发送多个分组而无需等待
-
以三倍为例
P.S.之所以下面的L/R不是三倍是因为当第三组的ACK到达的时候后前面已经又有两组发送了出去。
对于流水线,我们需要对分组有一定的处理
-
必须增加序号范围。流水线不像rdt只有0和1,对于可能存在的丢包等情况需要对特定的出现问题发分组处理。
-
发送方和接收方可能都要缓存多个分组。对于rdt只用缓存一的情况来说,因为流水线传输了多个,多个中不确定某个会出现问题,所以在发送方收到接收方回传的ACK之前发送方发出的分组需要缓存,接收方也需要缓存接收到的文件。
-
解决流水线的差错恢复有两种方法:回退N步和选择重传;
回退N步(GBN)
允许发送放发送多个分组,但是不可以超过N
如图window size是一个长度为N的窗口,其中包括了已发送但是发送方还没有收到相应ACK的分组和准备好但是还未发送的分组,当收到序号为send_base的ACK后相应窗口后移一个格(未出现异常时),并发送一个分组。
-
累计确认:当收到编号为n的分组的时候表示n和n之前的分组都已经正确接收到,窗口相应的需要移动正确数量的格子。
-
超时:GBN中的发送方同样具有计时器。计时器相当于”位于”send_base处(即相当于理论上应该收到的ACK的那个分组,窗口的最前面)。当这个分组收到相应的ACK之后次计时器停止,后面的分组的计时器开始计时(不是所有的分组一开始发送就开始计时,窗口之中只存在一个计时器)
异常处理
以窗口容量为6举例
-
发送方分组丢失:对于分组0,1接收方正确接收并回复ACK0,ACK1,发送方接收到ACK0,ACK1;但是分组2在向接收方传输的时候出现丢失的情况,之后的分组3,4,5被接收方正常收到。
-
接收方检测到分组2没有接收到,会把之后的分组3,4,5丢弃,并且每次当分组3,4,5到达接收方时会发送ACK1,当发送方计时器超时之后会将分组2,3,4,5,6,7同时发出,之后正常收到ACK后窗口移动,分组8,9,10,11,12,13依次发出。
-
-
ACK回传失败:接收方正确接收分组并正确回传ACK,但是在回传之中出现了ACK2丢失的情况
-
如果ACK3,ACK4,ACK5正常收到,则对发送方没有影响
-
如果ACK回传时丢失太多导致发送方计时器超时,则会将窗口中的分组2,3,4,5,6,7同时回传,回传之后只要接收到了ACK(可能是第一次延时到达的或者重传的)就会按照规则窗口移动,而接收方会将重复的丢弃。
-
缺点
GBN潜在的允许发送方用多个分组“填充流水线”,提高了利用率。但是当窗口长度和带宽时延都很大的时候,单个分组的错误就会引起GBN重传大量分组;当差错率增加,流水线可能会充满了大量不必要的分组,所以需要选择重传SR
选择重传(SR)
通过让发送方仅重传那些它怀疑在接收方出错(丢失或受损)的分组,从而避免不必要的重传。
发送方的重传是按需求的,并不像GBN那样是将一个出错的分组及其之后的全部重传,只需要重传没有收到ACK的分组(丢失或者超时)每个分组都要有自己的定时器;接受方只要收到相应的分组就会将相应分组的ACK回传,对于失序的分组先行缓存,当正确顺序的分组到达之后一起交付给上层
异常处理
对于上面的(a),接收方收到了pkt0,1,2,发送方收到了ACK0,1,2,发送了pkt3(虽然接收方没有收到),再次发送的pkt0相当于是第二波的pkt0,当接收方收到的时候只是认为pkt3没有收到,这是正常情况。
但是对于(b),接收方收到了pkt0,1,2,但是回传的ACK全部没有被发送方收到,发送方认为是第一波的pkt0,1,2没有发送成功,再次发送pkt0,但是对于接收方来说与(a)没有区别,但是这次收到的pkt0是第一波的,但是接收方会认为是第二波的,这样就会造成了整体性错误。
因此我们需要适当的将窗口长度变得长一点(窗口长度必须小于或者等于序号空间大小的一半)
3.5面向连接的运输:TCP
-
面向连接:一个进程向另一个进程发送数据之前,两个进程必须先握手(即必须相互发送某些预备报文段,以建立确保数据传输的参数)
-
全双工服务:若一台主机上的A进程和另一台主机上的B进程存在一条TCP连接,那么引用层数据可以从A流向B也可以B流向A。
-
点对点:在单个发送方和单个接收方之间的连接,不存在多播。
-
可靠,按序的字节流 。无报文边界。
TCP建立连接
三次握手
发起这个连接的被叫做客户进程,另一个进程被叫做服务器进程。客户进程首先发送一个特殊的TCP报文段,服务器进程用一个特殊的报文段来响应,最后客户进程再用第三个特殊报文段进行回应。
前两次报文段不承载有效载荷(即不包含应用层数据),第三个报文段可以承载有效载荷
发送数据
建立连接后就可以发送数据。客户进程通过套接字传递数据流,TCP将数据引导到该连接的发送缓存,发送缓存大小是在三次握手的过程中确定的;一个有趣的事情是,TCP规范中没有规定TCP应该在何时发送缓存里的数据,描述为“TCP应该在它方便的时候以报文段的形式发送数据”;
TCP为每块客户数据配上一个TCP首部,从而形成多个TCP报文段,这些报文段被下传到网络层,网络层将其分别封装在网络层IP数据报中,然后这些数据报被发送到网络之中。接收端收到报文段后,该报文段的数据就被放入该TCP连接的接收缓存中
MSS和MTU
TCP可从缓存中取出并放入报文段的数据数量受限于最大报文段长度(MSS),MSS通常根据最初确定的由本地发送主机发送的最大链路层帧长度(即所谓的最大传输单元MTU)来设置。一般来说,MSS+TCP/IP首部的长度要小于等于链路的MTU,而以太网和PPP链路的MTU都等于1500字节,TCP/IP的首部通常为40字节,所以MSS一般来说为1460字节。
注意MSS是指在报文段里应用层数据的最大长度,而不是包括首部的TCP报文段的最大长度。
组成
TCP的组成包括:一台主机上的缓存、变量和与进程连接的套接字,以及另一台主机上的另一组缓存、变量和与进程相连的套接字。
两台主机之间的网络元素(路由器、交换机、中继器)中没有为该进程直接分配任何缓存和变量
TCP报文段
TCP报文段由首部字段和数据字段构成,数字字段包括一块应用数据。MSS限制了报文段数据字段的最大长度。当发送一个大文件时,TCP通常是将文件划分成长度为MSS的若干块(最后一块通常小于MSS);交互式应用通常传送长度小于MSS的数据块
-
源端口和目的端口号:用于多路复用/分解来自或送到上层的数据
-
检验和字段
-
32比特序号和32比特确认号字段:用于实现可靠数据传输
-
16比特接收窗口字段:用于流量控制,用于指示接收方愿意接受的字节数量
-
4比特首部长度字段:该字段指示了以32比特的字为单位的TCP首部字段,由于TCP选项字段原因首部字段长度可变(通常选项字段为空,所以TCP首部字段典型长度为20字节)
-
可选与边长的选项字段:用于发送方和接收方协商最大报文段(MSS)长度时,火灾高速网络环境下用作窗口调节因子使用。首部字段还定义了时间戳选项。
-
6比特的标志字段
序号和确认号
TCP将数据看成无结构、有序的字节流(可以从TCP对于序号的使用上面看出)。所以序号是建立在字节流文件上面而不是报文段。报文段序号是该报文段首字节的字节流编号。
如图所示,假设一个数据流有500 000个字节,MSS为1000字节,TCP将其划分为500个报文段,首个报文段序号为0,下一个报文段的序号不是1而是第二个报文段起始数据1000的序号1000,第三个报文段序号是2000,以此类推。
对于确认号来说,主机A填进去的确认号是主机A希望从主机B接收到的下一字节序号。比如主机A已经接收到了0~232的所有字节,此时正打算发送一个报文段给B,主机A等待主机B发送233及以后的所有字节,那么主机A就会在发往B的报文段中填上233。
-
累计确认:假如出现失序接受情况,确认号只需要填写第一个等待的字节即可
-
对于失序分组(即此分组前面还有分组没有收到),接收方将时序分组保留等待缺少的字节以填补间隔,并不是直接丢弃。
Telnet:案例
Telnet是一种应用层协议(发送的数据没有加密)
A是发起连接(客户),B是服务器。客户和服务器的起始序号分别是42和79。
-
客户发送第一个报文段的序号就是42,由于还没有收到服务器任何数据,所以希望收到的是79,因此确认号是79;数据字段包含一字节的字符'C'的ASCII码。
-
服务器发送第二个报文段:他有两个目的,第一个目的是为服务器所收到的数据提供一个确认,在确认号里面填43表示已经收到了42,正在等待43;序号是79,这是服务器的起始序号。第二个目的是回显字段'C',第二个字段里面写的是字符'C'的ASCII码。确认是被服务器到客户的报文段捎带的。
-
客户第三个报文段:唯一目的是确认已从服务器收到数据,数据字段为空。序号是43,确认号是80
口诀是“抄A加S转个圈”(确认号ACK直接用做下一个的序号Seq,序号Seq加1为下一个的确认号ACK)
往返时间估计和超时
TCP有超时重传,这就需要我们去估计一个合适的往返时间(RTT)来作为决定超时时间。
估计往返时间
TCP使用一种Sample RTT的方法来估计RTT。Sample RTT就是从某报文段发出到收到对该报文段的确认之间的时间量。大多数TCP的实现是在某个时刻做一个Sample RTT测试(并不是为每一个报文段做一个测试)。TCP并不为已经重发的报文段做Sample RTT测试,它只为传输一次的报文段测量Sample RTT。
TCP一般来说通过均值Estimated RTT=(1-a)Estimated RTT+a×Sample RTT来计算因路由器的拥塞和端系统负载变化所导致变化的RTT。a一般取1/8;因为Estimated RTT表示最近的网络状况,所以其理应得到较大的权值;这种方法也被称为指数加权移动平均 除了估计RTT外,计算RTT的变化也ok的,RTT偏差DevRTT =(1-b)DevRTT+b×|Sample RTT-Estimated RTT|;其中b的推荐值为0.25;当Sample RTT变化较大的时候,DevRTT的值较大,当Sample RTT变化较小的时候,DevRTT就较小;
设置和管理重传超时间隔
TCP是如何考虑超时时间的呢?该时间因略大于测量的RTT,不易过小——容易引起不必要的重传,也不易过大——网络对于报文段丢失情况的反应就会变慢;最后TCP采用了如下计算方式:TimeoutInterval=Estimated RTT+4*Dev RTT;
当出现超时后,TimeoutInterval值将加倍。不管怎么样,一旦报文段收到并更新Estimated RTT后,就用上述公式再次计算TimeoutInterval
可靠数据传输
IP协议提供的是尽力而为的服务:不保证数据报的交付、不保证数据报按序到达、不保证数据报中数据没有损坏。TCP协议在IP协议之上,提供可靠数据传输,从而保证一个进程从其相关联的缓存中读取的数据和另一端进程发送的数据是一致的(确保一个进程从接收缓存中读出的数据流是无损坏、无间隙、非冗余、按序的数据流);TCP使用超时重传和冗余确认技术来处理超时、丢失等情况;使用确认、序号等技术来保证按序到达;使用校验和来检验是否报文段在传输过程中是否发生了错误;
与发送和重传有关的主要事件:
-
从上层应用程序接收数据→将数据封装在报文段中并交给IP
-
定时器超时 →以重传引起超时的报文段来响应,并重启定时器
-
收到ACK →判断收到的ACK序号是否正确
异常处理
-
ACK丢失 接收方收到重传的报文段后丢弃
-
发送两个报文段,接收方全部收到但第一个ACK超时 重传第一个报文段,并重启定时器(TCP只有一个定时器),只要在新的超时时间内第二个ACK到达就不重传第二个报文段
-
第一个ACK丢失但第二个正常到达
不重传任何一个
超时间隔加倍
如果出现了超时情况,那么TCP会重传报文段并将新的过期时间设置为原先的一倍,再超时再乘2。但是当定时器是因为收到上层数据和收到ACK这两个事件启动时TimeoutInterval由最近的EstimatedRTT值和DevRTT值确定。
快速重传
当有分组丢失但是丢失分组之后的分组到达,会发送已经接收到的最后一个按序字节数据进行重复确认
流量控制
TCP连接每一侧主机上面都有接收缓存,TCP接收到正确按序分组就将其放到接收缓存,但是接收方并不是立刻读取数据。如果发送方发的太快太多,接收缓存就会溢出。
在TCP连接的两端,各自维护着相关的变量:last Sent、last Acked。
接收缓存为RcvBuffer ,大小可通过socket选项来设定(缺省为4096字节)
TCP让发送方维护一个接收窗口,接收窗口可用rwnd来表示。主机B不当前rwnd的值放入发送给A的报文段的接收窗口字段,开始时接受窗口值=接收缓存,主机A已发送但是还未确认的数据量不可超过rwnd的值。
当rwnd = 0时若缓存清空,主机B并不会给A发消息告诉它rwnd的值有变化(TCP仅有在有数据或者有确认要发的时候才发送报文段),所以我们要求当B的接收窗口为0时A继续发送只有一个字节数据的文件的报文段,这些报文段会被接收方确认,最终缓存开始清空,确认报文段里面包含一个非0的rwnd值。
TCP连接管理
建立连接(三次握手)
-
第一步:客户端向服务器发送一个不包含应用层数据的报文段,报文段首部SYN比特位被置为,客户会随机选择一个初始序号(client_isn),放在序号字段。之后将报文段封装在IP数据报中送给服务器。
-
服务器从数据报中提取TCP SYN报文段并为TCP连接分配TCP缓存和变量,并向客户端发送允许连接的报文段。报文段不含有应用层数据,SYN比特被置为1,确认号字段被指为client_isn+1,并选择初始序号(server_isn)放在首部序号字段。此报文段被称为SYNACK报文段。
-
收到SYNACK报文段后客户也要为连接分配缓存和变量,这次回复的报文段中SYN比特被置为0,确认号字段server_isn+1,可以携带数据。以后每一个报文段的SYN都被置为0。
为什么连接建立需要三次握手,而不是两次握手?
防止失效的连接请求报文段被服务端接收,从而产生错误。
PS:失效的连接请求:若客户端向服务端发送的连接请求丢失,客户端等待应答超时后就会再次发送连接请求,此时,上一个连接请求就是『失效的』。
若建立连接只需两次握手,客户端并没有太大的变化,仍然需要获得服务端的应答后才进入ESTABLISHED状态,而服务端在收到连接请求后就进入ESTABLISHED状态。此时如果网络拥塞,客户端发送的连接请求迟迟到不了服务端,客户端便超时重发请求,如果服务端正确接收并确认应答,双方便开始通信,通信结束后释放连接。此时,如果那个失效的连接请求抵达了服务端,由于只有两次握手,服务端收到请求就会进入ESTABLISHED状态,等待发送数据或主动发送数据。但此时的客户端早已进入CLOSED状态,服务端将会一直等待下去,这样浪费服务端连接资源。
拆除连接(四次挥手)
-
客户向服务器发送一个终止报文段,其中FIN比特被置为1。
-
服务器发送一个确认报文段。
-
服务器发送自己的终止报文段,FIN比特置为1。
-
客户对服务器终止报文段确认。此时客户进入TIME-WAIT状态。该状态会持续2MSL时间,若该时间段内没有服务器的重发请求的话,就进入CLOSED状态,撤销TCP。当服务器收到确认应答后,也便进入CLOSED状态,撤销TCP。
为什么客户要先进入TIME-WAIT状态,等待时间后才进入CLOSED状态?(第四次挥手之后)
为了保证服务器能收到客户的确认应答。 若客户发完确认应答后直接进入CLOSED状态,那么如果该应答丢失,服务器等待超时后就会重新发送连接释放请求,但此时客户已经关闭了,不会作出任何响应,因此B永远无法正常关闭。
异常处理
-
一台主机接受了具有8端口的TCP SYN分组,但是该主机在80端口不接受连接,就会向源主机发送一个特殊重置报文段,在这之中RST标志位置为1
-
主机接收到一个UDP分组,他的目的端口号与进行中的UDP套接字不匹配,该主机发送一个特殊的ICMP数据报
拥塞控制原理
原因:
-
太多的源
-
网络中有大量的数据
-
源以过高的速率发送数据
后果:
-
丢失数据分组 (路由器缓存溢出)
-
长时间的延迟 (在路由器的缓存中排队)
以几个理想情景举例
-
情景1:无限缓存,无重传
带宽R两条链路平分,一边R/2,但是路由器处理能力有限但是缓存无限,当λin速率增大时λout最大就是R/2,当λin越来越大时延迟就会越来越长
0<λin< R/2 λout = λin
λin > R/2 λout = R/2
当λin接近 R/2时,时延急速变大
-
情景2:路由器有限缓存,有重传
重传导致 λ’in大于λout
-
情景3:发送方只在有缓存的情况下发送,这种情况下没有丢失情况
-
情景4:发送方知道具体哪个分组是真正丢失的(不是因为超时原因而认为是丢失的)
在速度相对来小的时候来说是线性增加,但是当速度接近R/2因为重传的原因导致 λ’in中会有正常传输和重传两部分。
虽然会有丢失的情况,但是因为发送方知道具体哪个分组是真正丢失的,不会出现有相同的分组到达接收端的情况,所以当 λ’in很大的时候接收端的接受速率可以到达R/2
-
实际情况
-
分组由于缓存满而被路由器丢弃
-
发送方过早超时,使得原始分组(只是推迟但未丢弃)和重发的分组都被送至接收方,导致到达的到不了R/2
-
-
四个主机,每次传输经过两个路由器
以路由器R1为例,有红色和蓝色两条传输链路,红色离得近(这是红色的第一个路由器,而蓝色是第二个),当 λ’in比较小的时候是线性上升,但很大的时候就会出现红色的把蓝色的份额挤掉了,导致前面的传输全部白费。因此可以选择优先考虑已经经历过上有路由器的分组。
拥塞控制方法
-
拥塞控制:拥塞控制是作用于网络的,它是防止过多的数据注入到网络中,避免出现网络负载过大的情况;
-
流量控制:流量控制是作用于接收者的,它是控制发送者的发送速度从而使接收者来得及接收。
总体来说,我们可以更具网络层是否为传输层拥塞控制提供了显式帮助来区分拥塞控制方法:端到端拥塞控制和网络辅助拥塞控制;
端到端拥塞控制
在端到端拥塞控制方法中,网络层并没有向传输层拥塞控制提供显式支持,即便网络中存在拥塞,端系统也必须通过对网络行为的观察(如分组丢失与时延)来判断;TCP必须通过端到端的方法解决拥塞控制,因为IP层不会像端系统提供有关网络拥塞的反馈信息。TCP报文段的丢失(超时或者收到3次冗余确认而得知)被认为是网络拥塞的一个迹象,TCP将相应地减小窗口长度;
网络辅助的拥塞控制
在网络辅助的拥塞控制方法里,网络层会向发送方提供关于网络中拥塞状态的显式反馈消息;比如使用一个比特位来指示网络是否拥塞;
拥塞信息从网络反馈到发送方一般有两种方式,其中直接反馈信息可以由网络路由器发送给发送方,这种方式的通知通常采用一种拥塞分组的形式(主要是说“我拥塞了”;第二种形式的通知是路由器标记或者更新从发送方到接收方的分组中的某个字段来指示拥塞的产生,然后由接收方向发送方通知该网络发生了拥塞。
ABR: available bit rate(可用数据速率)
-
“弹性服务”
-
如果发送方的路径“欠负载” ,发送端应该把带宽用足
-
如果发送端路径拥塞,发送端将其数据速率约束到最小承诺速率
RM (resource management) cells(资源管理信元)
-
由发送端发送, 掺和在数据信元一起
-
在 RM 信元中的数据位由交换机设定 (“网络辅助”)
NI bit: 不得增加发送速率 (轻微拥塞)
CI bit: 拥塞指示
-
RM信元由接收端返回给发送端, 所有数据位保持原样
TCP拥塞控制
原理
TCP必须使用端到端拥塞控制而不是网路辅助的拥塞控制,因为IP层不向端系统提供现实的网络拥塞反馈
TCP使用的方法是让每一个发送方根据所感知到的网络拥塞程度来限制其能向链接发送流量的速率:没拥塞就提升速率,有拥塞讲就降低速率。但是有三个问题:1.一个TCP发送方如何限制它向其连接发送流量的速率?
2.一个TCP发送方如何感知从它到目的地之间的路径上存在拥堵?
3.发送方感受到了拥堵,采用何种算法来改变其发送速率?
TCP链接的每一端都是由一个接收缓存,一个发送缓存和几个变量(LastByteRead,rwnd等)组成,运行在发送方的TCP拥塞控制机制跟踪一个额外变量,叫做拥塞窗口(cwnd),它对TCP发送方能向网络中发送流量的速率进行了限制,特别是在一个发送方未被确认的数据量不会超过cwnd和rwnd的最小值,即 LastByteSent - LastByteRead ≤ min {cwnd,rwnd}
我们假设TCP接收缓存足够大以至于可以忽略接收窗口的限制;假设发送方总是有数据要发送,即拥塞窗口中的所有报文段都要被发送;考虑一个丢包和时延均忽略不计的链接。粗略地讲,在每个往返时间(RTT)的起始点,上面的限制条件允许发送方向该连接发送cwnd个字节的数据,在RTT结束的时候发送发接收对数据的确认报文,所以发送方的发送速率大概是cwnd/RTT 字节/秒,调节cwnd的值能调整发送方向连接发送数据的速率(拥塞窗口是动态的)。
对于TCP发送方感知它与目的地之间出现了拥塞,将TCP发送方的“丢包事件”定义为:超时或者收到三个冗余ACK。
对于TCP发送方确定他们的发送速率,有如下几个原则:
-
当出现丢包事件时应该就降低速率
-
对于先前未确认的报文段到达的时候,可以增加速率
-
带宽检测
加增 乘减 AIMD算法
方法: 发送方逐步增加传输速率(window size),刺探可用带宽,直到分组丢失
-
加法增加:每一个RTT后cwnd增加1MSS(最大报文长度)长度,直到分组丢失检测到
-
乘法减少:分组丢失检测到后,cwnd减半
AIMD 呈现锯齿状---刺探带宽
TCP拥塞控制算法
包括三个主要部分:慢启动,拥塞避免,快速恢复。其中慢启动和拥塞避免时TCP的强制部分。慢启动比拥塞避免能更快的增加cwnd的长度
慢启动
当TCP连接开始的的时候,cwnd通常设置为一个MSS的较小值,初始发送速率即为MSS/RTT bps;慢启动状态下cwnd以一个MSS开始传送,每当传输报文段被确认就增加一个MSS,之后cwnd就变为2再次传输,这两个每被确认就增加一个MSS,都确认之后cwnd就变为4,以此类推。
对于何时结束这种指数增长,有几种情况:
-
对于由超时指示的丢包现象,TCP发送方将cwnd设置为1,并重新开始慢启动;还将“慢启动阙值”ssthresh设置为cwnd/2
-
第二种是当cwnd到达或超过ssthresh时再次翻倍可能会有不妥,因此结束慢启动状态进入拥塞避免状态
-
最后是检测到三个冗余ACK的时候,TCP执行一种快速重传并进入快速恢复状态
拥塞避免
进入拥塞避免状态的时候cwnd大概是上次遇到拥塞时的一半,所以每个RTT只将cwnd增加1个MSS
对于何时结束拥塞避免,有几种情况:
-
出现超时的丢包情况(Tahoe TCP)时,ssthresh被更新为cwnd的一半,cwnd被设置为1,进入慢启动状态;
-
出现三个冗余的丢包情况(Reno TCP) 时,重复的ACKs 表明网络仍然有传输能力,变化没有那么剧烈,只是将cwnd减半,更新ssthresh为cwnd一半,接着进入快速恢复状态。
快速恢复
快速恢复中对于引起TCP进入快速恢复的缺失报文段,对收到的每个冗余的ACK,cwnd增加一个MSS。最终,当对丢失报文段的最后一个ACK到达的时候,TCP降低cwnd之后进入拥塞避免状态。如果出现超时状态,快速恢复执行如同在慢启动和拥塞避免一样的动作,之后进入到慢启动状态:丢包出现时cwnd被设置为1,ssthresh更新为cwnd的一半。
在第八个传输回合出现三个冗余ACK,ssthresh被更新为0.5*cwnd = 6,Reno中cwnd被设置为9(6+3,这个3时三个冗余ACK),而Tahoe中cwnd被设置为1
吞吐量的考虑
宏观描述
当考虑一个TCP连接到平均吞吐量时,通常忽略慢启动阶段(因为这个阶段指数增长,比较短),窗口长度w,往返时间是RTT,那么速率是w/RTT,每个RTT增加一个w,直到丢包事件。那么TCP平均吞吐量 = 0.75* W/RTT Bps
高带宽路径
@ 例子:1500字节报文段,100msRTT,10G发送速率
需要拥塞窗口大小为83333个报文段
吞吐量和包丢失概率关系
T = 1.22*MSS/(RTT)
T≥10Gbps 则L = 2*10 -10次方 非常小的概率,所以需要设计新的TCP