-
传输层
- 模型中的位置:位于应用层和网络层之间,是分层的网络体系结构中重要的部分
- 作用:
- 该层为运行在不同主机上的应用进程提供直接的通信服务起着至关重要的作用。
- 问题:
- 如何实现在两个端系统上不同的应用进程之间通信的可靠传输?
- 拥塞的后果和原因?
- 常见的拥塞控制手段有什么?
-
概述和运输层服务
- 传输层协议为运行在不同端系统上的应用进程之间提供逻辑通信功能;
- 应用层进程使用传输层提供的逻辑通信功能而无需考虑实现通信的物理基础设施的细节;
- 传输层协议是在端系统中实现的而不是在路由器中实现的
- 传输过程:
- 传输层接收来自应用层的报文并通过添加传输层首部以生成传输层报文段。
- 在生成过程中可能会对来自应用层的报文加以分割;
- 在发送端系统中,运输层会将这些报文段交给网络层;网络层将其封装成网络层分组,也被称为数据报,然后向目的地发送。路由器不会检查封装在数据报中的传输层报文段的字段;
- 在接收端系统中,网络层从数据报中抽取传输层报文段,并将其交给传输层,传输层接收到报文段后,使该报文段中的数据被接收进程所使用
- 网络应用可以使用多种传输层协议,因特网有两种传输层协议:
- TCP
- UDP
- 不同的传输层协议提供不同的运输层服务
- 不过在UDP之上运行多媒体应用是有争议的,因为UDP没有拥塞控制协议,所以其对网络有很大的威胁性:
- 大量的UDP流量将使网络过度拥塞而造成UDP连接几乎无法传输数据,并且因为网络拥塞,所以应用又有着较高的丢包率。也有研究人员提出一些新的机制,使得所有数据源,包括UDP源执行自适应的拥塞控制来解决这一问题;
-
传输层和网络层的关系
- 网络层提供主机之间的逻辑通信
- 而传输层为运行在不同主机上的应用进程提供逻辑通信
- 运输层协议只工作在端系统中,在端系统中,传输层协议将来自应用进程的报文移动到网络边缘即网络层 ,同样也从网络层接收这些报文段,传输层对报文段如何在网络核心传输并不做干涉;
- 中间路由器既不处理也不识别传输层加载应用层报文上的任何信息
-
网络层对传输层(由下到上,分层模型)的影响:
- 传输层协议能提供的服务常常受制于底层网络层协议的服务类型
- 如果网络层协议无法为主机之间的通信提供时延和带宽保证的话,运输层协议也就无法为进程之间发送的应用程序报文提供时延或者带宽保证.
- 即使底层网络协议不能在网络层提供相应的服务,传输层协议也能提供某些服务。例如,即使底层网络协议是不可靠的,造成分组冗余、丢失和篡改,运输协议也能为应用程序提供可靠的数据传输服务。
-
因特网传输概述
- 因特网为应用层提供了截然不同的两种传输层协议:
- UDP(用户数据报协议):一种不可靠、无连接的服务
- UDP不提供拥塞控制,使用UDP传输的应用程序可以根据需要以任意的速率发送数据。
- TCP:提供可靠的,面向连接的服务
- TCP提供额外的服务,首先它是一种可靠数据服务,这意味着TCP协议保证数据的按序、完整地从发送端应用进程发送到接收端应用进程;
- TCP通过序号、确认、定时器以及流量控制来将IP的不可靠数据传输转换为可靠数据传输;
- TCP提供拥塞控制,拥塞控制与其说是一种提供给应用程序的服务,不如说是一种提供给整个网络的服务,因为整个网络都将因为拥塞控制而受益;不太严格地说,拥塞控制力求为每一个经过一条拥塞网络的连接提供平等的共享网络链路带宽,从而避免一条TCP连接用过多的流量来淹没通信主机之间的链路和设备;拥塞控制是通过调节发送进网络的的流量速率来做得到;
- 运输层分组也被称为报文段
- UDP和TCP最基本的责任就是将IP提供的主机间交付服务扩展到不同端系统上两个个进程之间的服务。这也被称为传输层的多路分解和多路复用;
- UDP和TCP通过在传输层首部添加差错检查字段来提供完整性检查。
- 进程到进程之间的数据交付和差错检查是最低限度的两种传输层服务,也是UDP可以提供的仅有的两种服务。
- UDP(用户数据报协议):一种不可靠、无连接的服务
- 因特网的网络层:
- 网络层协议有一个名字即IP,即网际协议。
- 作用: IP为主机间提供逻辑通信,IP的服务模型为尽力而为交付服务(best-effort delivery service)这意味着IP尽最大的努力在主机间交付报文段,但是不做任何保证。它不保证报文段的交付、不保证报文段按序交付、不保证报文段中数据的完整性;即IP提供一种不可靠的服务;每台主机都需要有一个网络层地址,即IP地址。
- 因特网为应用层提供了截然不同的两种传输层协议:
-
多路复用和多路分解
- 有前面的介绍,我们可以知道,传输层将网络层提供的面向主机的逻辑通信扩充为面向不同应用进程的逻辑通信,并且这一过程称为多路复用和多路分解;值得注意的是,多路复用和多路分解是每个计算机网络都需要的
- 实际上,传输层和应用程序进程之间通过Socket(套接字)关联,这样通过Socket就可以区别同一主机上的不同应用进程,从而传输层提供服务变为可能
- 传输层从同一台主机上的不同Socket接收数据的过程称为多路复用;
- 传输层向同一台主机上的不同Socket传输数据的过程称为多路分解;
- 为了实现多路复用和多路分解,我们需要标志套接字,并将相关信息添加到报文段中。
- 端口号:
-
实际上,每个套接字都有一个唯一的标识符(ID),被称为端口号(16比特);
-
在传输层接收到来自应用程序的分组并通过添加传输层首部而形成报文段的过程中,该端口号被写入;端口号大小在0-65535之间,其中0-1023属于周知端口号,它们为特定的Socket而拥有。
-
无连接的多路复用与多路分解:
- 需要注意的是,在创建Socket的时候,是由传输层为之分配端口号(1024~65535);
- 一个UDP套接字是由一个目的IP地址和目的端口号即二元组来标志的
- 如果两个UDP报文段有不同的源IP地址或者源端口号,但是有相同的目的IP和目的端口号的话,它们将通过同一个Socket到达同一个应用程序 (因为它们只通过目的IP地址和端口号来标识,和源的IP地址端口号无关)
- 而这里的源端口号的作用就是当作“返回地址” 的一部分,由接收进程做出响应,也就是在响应报文段中将源端口号和源IP地址当作目的端口号
-
面向连接的多路复用与多路连接:
- TCP协议中的Socket是通过一个四元组来标记的:(源IP地址,源端口号,目的IP地址,目的端口号);
- 两个具有不同源IP地址或者源端口号,但有相同的目的IP地址和目的端口号的TCP报文段将通过两个不同的Socket进入同一应用进程;(标识的不同带来的不同的结果)
- 这也表示,一个(应用)进程可以关联多个Socket,而一个Socket将只关联一个应用进程;常常,这样的对应关系是通过线程来实现的:一个进程有多个线程,而每个线程关联了一个Socket;这样做可以提高服务器性能
-
实际上,传输层就是根据这些信息来实现多路分解的;而这些信息是在多路复用的时候被放置在报文段中
-
-
无连接运输:UDP
- 前面提到过,差错检查和进程到进程的数据交付是传输层协议必须提供的功能,UDP制作到了这两个功能(少量的差错检查),几乎没有对IP增加别的功能。
- 如果我们使用UDP,则应用程序差不多直接和IP打交道
- 无连接是什么?
- 因为在发送报文段之前,发送方和接收方的传输层实体之间没有握手,所以UDP也被称为无连接的;
- 使用UDP协议的应用层协议:
- DNS: UDP在接收到来自Socket的数据时,UDP为该报文添加首部字段(源端口号和目的端口号,以及其他两个小字段),然后将报文段交给网络层,网络层将此UDP报文段封装进一个IP数据报中,然后发送给一个名字服务器,当DNS客户端等待不到对该查询的响应时(有可能网络层将其丢失了)则会向其他名字服务器发送查询请求,要么就通知应用程序。
- 既然TCP提供了可靠数据传输,并且提供了拥塞控制,为什么人们还需UDP呢?
-
事实上,有些应用很适合UDP(因为没有连接过程啊,因为不会受拥塞控制的调节啊,更自由);
-
UDP的优点:
- 关于何时、发送什么数据的应用层控制更为精细(实时应用中实用):这是因为一旦应用程序将数据交给UDP,UDP就会打包将其发送给网络层,不会受到传输层的调节, (应用程序还可以通过UDP+自主开发一些功能的模式来扩展UDP)。
- 无需建立连接(减小时间开销): 所以就不会引入额外的时延。这也可能是DNS使用UDP而不是TCP的主要原因,如果使用TCP的话,DNS服务将会慢很多;HTTP使用TCP的主要原因是对TCP的可靠性的依赖超过对速度的要求;
- 无需维护连接状态(减小空间开销):TCP为了实现可靠数据传输和拥塞控制需要在端系统中维护一些参数,这些参数包括:接收和发送的缓存、拥塞控制参数、确认号和序号;这些参数信息都是必须的;而UDP因为不建立连接,所以自然也就不需要维护这些状态,这就减少了时间和空间开销;
- 注意: 需要注意的是,使用UDP仍然可以实现可靠数据传输,只不过这一部分功能需要在应用程序中自主开发;将可靠性直接构建于应用程序中,将使其既可以可靠地传输数据又可以避免受制于TCP的拥塞控制(传输速率的控制)
- 分组首部更小: TCP有20字节的首部开销,而UDP只有8字节
-
UDP报文结构:
-
UDP首部只有4个字段,每个字段占用两个字节,分别是:源端口号、目的端口号、长度和校验和;
- 长度: 表示包含首部在内的UDP报文段长度,以字节为单位;
- 校验和: 字段用来计算报文段在传输的过程中是否出现了差错;
- 一种常见的校验和的计算方法:发送方将前三个字段做按位加运算,然后将其取反作为校验和;然后接收方对所有四个字段(每个字段16位)(包括校验和)进行求和,如果没有出现差错,则最后的结果全是1,否则就表明出现了错误;
- 出现错误的原因可能有:
- (链路层)传输链路上数据受到噪声干扰、
- (网络层)数据存储在中间路由器的时候,出现了错误
-
UDP作为传输层协议,提供的差错检测功能很有可能和底层协议提供的相似功能产生冗余:
- (链路层的差错检查功能) 因为由于不能保证源和目的地之间所有链路都提供差错检测功能
- (网络层的差错检查功能) 即便数据在链路上正确传输,也无法保证其在中间路由器的内存中不会引入比特错误;
- (传输层的差错检查功能) 所以要实现端到端的差错检测,就必须在传输层协议中实现该功能;这一原则在系统设计中被称为端到端原则:
- “因为某一功能必须基于端到端实现,与在较高层次提供这些功能的代价相比,在较低层次上设置的功能可能是冗余的,或者根本是没有用的(较低层实现的代价大么?应该吧)”
-
IP作为网络层协议,可以运行在任何第二层协议上,所以传输层提供差错检测也是非常有用的;
-
UDP可以检测差错,但是无法恢复差错,能做的除了将其丢弃外,便是将其交给应用程序然后给出警告.
-
-
可靠数据传输原理:
- 可靠数据传输的问题,不仅在传输层需要考虑,在链路层以及应用层都需要考虑这个问题,所以了解一些其基本原理是必要的,特别是在详细了解TCP中为实现可靠数据传输而采取的。
- 可靠数据传输为上层实体提供的服务抽象是:数据可以通过一套可靠的信道进行传输,借助于可靠信道,传输数据就不会受到损坏或者丢失;并且所有数据都可以按照其发送顺序进行交付。而这正是TCP向调用它的应用所提供的服务模型
- 实现这种抽象服务是可靠数据传输的责任,但是因为可靠数据传输的底层协议可能是不可靠的,所以这项任务有一点困难;
- 单方向的可靠数据传输流程大概是这样的:可靠数据传输->不可靠数据传输->不可靠的传输信道->可靠数据接收->上传Data
- 构造可靠信道的可靠数据传输:
- 一个可靠数据传输协议,将要面对以下问题:分组丢失(丢包)、分组损坏到达、分组乱序到达
- 总结可靠传输需要的技术:检验和、序号、定时器、肯定和否定确认分组。
- 底层信道是完全可靠的:rdt 1.0
- 最简答的情况,底层信号完全可靠,然而这在实际中不能实现
- 并且在这个简单的协议中,一个单元数据和一个分组没差别
- 接收端就不需要提供任何反馈信息给发送方,因为不会担心出错
- FSM(有限状态机):
- 经具有比特差错信道的可靠数据传输:rdt 2.0
- 底层信道更为实际的模型是分组中的比特可能受损的模型(这种比特差错通常会出现在网络的物理部件中)
- 假设所有发送的分组都可以按其发送顺序被接收。
- 基于重传机制的可靠数据传输协议称为自动重传请求协议(ARQ)。
- ARQ协议中还需要另外三种协议功能来处理存在比特差错的情况:差错检测,接收方反馈,重传。
- 差错检测: 需要一种机制以使接收方检测到何时出现了比特差错
- 接收方反馈:
- ACK:肯定确认,1表示
- NAK:否定确认,0表示
- 重传: 接收方收到有差错的分组时,发送方将重传该分组。
- rdt2.0的发送端每发送一个分组需要等待接收端的确认信号(ACK或NAK),这种协议被称为停等协议。
- rdt 2.1(rdt 2.0 的改进)
- rdt 2.0 中有一个致命的缺陷,就是没有考虑到 ACK 和 NAK 分组受损的可能性。
- 考虑ACK和NAK受损的两个可能性:
- 增加足够的校验和比特,使发送方不仅可以检测差错,还可恢复差错
- 当接受到模糊不清的ACK和NAK分组时,只需要重传当前数据分组。这引入了冗余分组
- 冗余分组的根本困难在于接收方不知道它上次所发送的ACK和NAK是否被发送方正确接收到。因此它无法事先知道接收到的分组是新的还是一次重传。
- 考虑ACK和NAK受损的两个可能性:
- 解决这个新问题的一个简单的方法就是在数据分组中添加一个字段,让发送方对其数据分组编号,即将发送数据分组的 序号 放在该字段。于是,接收方只需要检查序号即可确定收到的分组是否一次重传。对于停等协议这种简单的情况,1 比特的序号就足够了(因为通过这个序号是否和前一个分组的序号相同,判断是否是一个新分组还是重传)(目前我们假定分组不在信道丢失,所以ACK和NAK分组本身不需要指明它们要确认的分组序号,发送方就当作ACK和NAK分组是为响应其最近发生的数据分组生成的)。
- rdt2.1的发送方和接收方FSM的状态数都是以前的两倍。因为协议状态必须反映出目前(由发送方)正发送的分组或(在接收方)希望接收的分组的序号是0还是1(发送或期望接收0号分组的状态中的动作与发送或期望接收1号分组的状态中的动作是相似的:唯一的不同是序号处理的方法不同)。
- rdt 2.0 中有一个致命的缺陷,就是没有考虑到 ACK 和 NAK 分组受损的可能性。
- rdt 2.2
- 如果不发送NAK,而是对上次正确接收的分组发送一个ACK,我们也能实现同样的效果。
- 发送方接收到对一个分组的两个ACK(冗余ACK)后,就知道接收方没有正确接收到跟在确认两次的分组后面的分组。
- rdt 2.2 是在有比特差错信道上实现的一个无NAK的可靠数据传输协议。
- rdt 2.1和rdt 2.2的区别在于,接收方此时必须包括由一个ACK报文所确认的分组序号(明确知道哪个分组有接收到,还是没接收到)
- 经具有比特差错(分组损坏到达)的丢包(分组丢失)信道的可靠数据传输:rdt3.0
-
现在假定除了比特受损外,底层信道还会丢包。因此协议还要处理另外两个问题:
- 怎样检测丢包?
- 丢包后该做些什么?
-
在 rdt 3.0 中,丢包的问题让发送方解决(当然也有很多方法用于解决丢包问题)。不管是发送的分组丢失,还是接收方返回的确认分组丢失,只要在经过一定的时延后,让发送方重发该分组即可。
- 这段时延是多少呢?
- 至少需要:发送与接收方之间的一个往返时延+中间路由器的缓冲时延+接收方处理一个分组所需的时间
- 经过这段时延的时间,则称重传。
- 这段时延是多少呢?
-
由此产生的 冗余数据分组 则由接收方通过序号(协议rdt2.2中就这样解决)处理。为了实现基于时间的重传机制,需要一个倒计时定时器
- 如果一个分组经历了一个特别大的时延,发送方可能重传该分组,即使该数据分组及其ACK都没丢失,这就在发送方到接收方的信道中引入了“冗余数据分组”的可能行。
- 倒计时定时器:
- 在一个给定的时间量过期后,可中断发送方。
- 发送方需要做到:
- 每次发送一个分组时,便启动一个定时器。
- 响应定时器中断(采用适当的动作)
- 终止定时器中断
- 发送方需要做到:
- 在一个给定的时间量过期后,可中断发送方。
-
因为分组序号在 0 和 1 之间交替,因此 rdt 3.0 有时被称为 比特交替协议。
- 分别看一下不同情况下的分组传输:(注意到一个分组的接收时间必定迟于一个分组的发送时间,这是发送时延与传播时延之故)
- 从图中看为什么rdt3.0被称为比特交替协议
-
- 流水线可靠数据传输协议
- rdt3.0的核心问题在于他是一个停等协议,因此性能很差。
- rdt 3.0 是一个功能正确的协议,但是由于它是一个停等协议,大部分的时间都浪费在等待确认上面,所以性能不好。
- 解决这种特殊性能问题的一个简单的方法是:不使用停等方式运行,允许发送方发送多个分组而无需等待确认。这种技术被称为流水线。
- 停等协议:
-
设包括首部字段和数据的分组长为L=1000字节(8000比特),则发送一个分组进入1Gbps链路实际所需时间是:
-
该分组的最后1比特在时刻 t 时到达接收方 ,t=RTT/2+L/R = 15.008ms到达接收方
-
接收方一旦收到一个数据分组的最后1比特后立即发送ACK,ACK在时刻t=RTT+L/R=30.008ms时在发送方出现
-
因为发送方只用了0.008ms,则利用率为:
-
通过一个图对比:
-
要使用流水线技术,则须:
- 增加序号范围(不能只是停等协议中的0,1)。因为要传送多个分组,而每个传输中的分组必须有一个单独的序号。
- 协议的发送方和接收方两端必须能缓存多个分组。发送方至少得能缓存那些已发送但未确认的分组,而接收方或许也需要缓存那些已经正确接收的分组。
- 所需序号的范围和对缓冲的要求取决于数据传输协议如何处理丢失、损坏及延时过大的分组。
-
流水线的差错恢复有两种基本方法:
- 回退 N 步(GBN)
- 选择重传(SR)
-
- 回退N步:
- 允许发送方发送多个分组(当有多个分组可用时)而不需要等待确认,但它也受限于在流水线中未确认的分组数不能超过某个最大允许数N。
- base(基序号): 窗口的起点
- 下一个序号(nextseqnum): 表示上层需要发送分组时,可以使用的序号
- 通过图可知,我们把序号分成了4段,(仔细看图!)
- 0~base-1:这一部分的分组是已发送且收到接收方确认的分组
- base~next Sequence-1:这一部分的分组是已发送但是尚未收到确认的,其中base是尚未收到确认的最小序号;
- next-1~base+N-1: 表示当前发送方可以使用的序号,表示一种发送能力
- 当发送方收到确认号为base的确认分组后就会向前(图中向右)移动窗口,所以回退N步也被称为滑动窗口协议
- 这是发送方需要维护的数据,同时发送方需要响应的事件有:上层调用、收到ACK、超时事件;
- 上层调用: 检查next Sequence是否在窗口之内,如果在,这说明发送方还有发送能力,发送即可
- 收到ACK: 回退N步策略对序号为n的分组采取累积确认的方式,即当收到序号为n的ACK时,表明序号小于等于n的分组全部到位;
- 超时事件: 如果发生超时事件,那么发送方会重发所有已发送但是未确认的分组,即分组号在base和next sequence-1之间的所有分组;这也是为什么叫“回退N步”。如果收到一个ACK,则定时器会重新启动;如果没有待确认的分组,定时器将被终止 (发送窗口大于1,接受窗口等于1)
- 也就意味着如果某一个报文段出现错误,那么接收窗口会再次停留,之后收到的数据将会被丢弃:
- 优点: 在于接收缓存简单,即接收方不需要缓存任何失序分组
- 缺点: 丢弃一个正确接收的数组的缺点是随后对该分组的重传也许会丢失或出错,因此甚至需要更多的重传;
- 选择重发(SR)(回退N)
- 回退N步协议存在一个问题就是当窗口和带宽的时延都较大时,单个分组的差错可能会引起GBN重传大量的分组,然后许多本来不用重传的分组会充斥在信道中,造成资源浪费;
- 选择重传就是让发送方仅重传那些丢失和受损的分组而避免不必要的重传
- 顾名思义,选择重传(SR)协议通过让发送方仅重传那些它怀疑在接收方出错(即丢失或受损)的分组而避免了不必要的重传。这种个别的,按需的重传要求接收方逐个地确认正确接收的分组。再次用窗口长度N来限制流水线中未完成、未被确认的分组数。不过,与GBN不同的是,发送方已经收到了对窗口某些分组的ACK。
- SR 发送方的事件和动作:
- 从上层接收数据: 检查下一个可用于该分组的序号,若在发送方的窗口内,则将数据打包发送。
- 超时: 定时器再次用来防止丢失分组。但是现在每个分组必须得有单独的定时器。
- 收到 ACK: 倘若该分组序号在窗口内,则 SR 发送方将那个被确认的分组标记为已接收。如果该分组的序号等于send_base,则窗口基序号 向前(相当于图中向右) 移动到具有最小序号的未确认分组处。如果窗口移动了并且该序号落在窗口内的未发送分组,则发送这些分组。
- SR 接收方的事件和动作:
- SR接收方将确认一个正确接收的分组而不管其是否按序。失序的分组将被缓存直到所有丢失分组(即序号更小的分组)皆被收到为止,这时才可以将一批分组(就是连续的分组) 按序交付给上层。
- 序号在 [rcv_base, rcv_base + N -1] 内的分组被正确接收:在此情况下,收到的分组落在接收方的窗口内,选择 ACK 被回送给发送方。如果该分组以前没收到过,则缓存该分组。如果该分组的序号等于接收窗口的基序号,则该分组及以前缓存的序号连续的分组交付给上层。
- 序号在 [rcv_base - N, rcv_base - 1] 内的分组被正确接收。在此情况下,必须 产生一个 ACK,即使该分组是接收方以前已确认过的分组。
- 其他情况:忽略该分组。
- 接收方将确认一个正确接收的分组而不管其是否按序;失序的分组被缓存,直到形成连续数据后将其提交给上层; 值得注意的是,如果接收方收到了已经确认的分组,则说明确认ACK丢失,或者时延太长,接收方和发送方沟通不及时;这也表明了关于那些分组到位了,那些分组还没到位,接收方和发送方有着不一样的视图。
- 另外还需要注意的是,序号的重用问题,如果在分组中序号字段的位数为k,那么最大的序号为2^k-1,所以有可能不同分组同时占用一个序号,为了避免这种情况,需要做的是控制分组的生命周期。窗口长度必须小于或等于序号空间大小N的一半。
- 为什么窗口长度必须小于或等于序号空间大小N的一半(下图中看不出是第一个分组的重传还是第5个分组的初次传输)?
- SR接收方将确认一个正确接收的分组而不管其是否按序。失序的分组将被缓存直到所有丢失分组(即序号更小的分组)皆被收到为止,这时才可以将一批分组(就是连续的分组) 按序交付给上层。
- 通过图可知,我们把序号分成了4段,(仔细看图!)
- 可靠数据传输机制和用途总结:
- 允许发送方发送多个分组(当有多个分组可用时)而不需要等待确认,但它也受限于在流水线中未确认的分组数不能超过某个最大允许数N。
-
面向连接的TCP(传输控制协议)
- TCP连接
- TCP协议之所以被称为是面向连接的协议,是因为在一个应用进程可以向另一个应用进程发送数据前,这两个进程将首先“握手”,即它们必须相互发送某些预备报文段,以建立对关于数据传输的参数的;作为TCP连接建立的一部分,通信双方都将初始化与TCP连接的许多状态变量
- TCP的连接,其连接状态被端系统所维护而中间路由器完全忽略了该协议,中间路由器看到的只是数据报,而不是链接,也就是说,TCP只运行在端系统之上;所以,TCP连接更像一种**状态(逻辑连接)**而不是物理的、实际的连接。
- TCP提供全双工服务:
- 数据从A到B的同时,也能从B到A;
- TCP是点对点的:也就是说TCP协议无法提供“多播”服务,一条TCP连接只关联一个发送方和接收方( 当然,发送方也是接收方);
- 对于TCP建立过程中的 “握手”阶段 ,需要明白的是,手一共握了三次,前两次报文段不承载“有效负载”,第三次握手的时候,报文段是可以装载“有效负载”的;这个过程是这样的:
- 通信的发送方首先发送一个特殊的TCP报文段给接收方,这是第一次握手;
- 接收方收到该报文段后,对该报文段进行响应,此为第二次握手;
- 发送方接收到响应报文段后,发送第三个报文段,其中包含了**有效负载,**此为,第三次握手;
- 因为TCP建立的过程,一共发生了三次握手,所以该过程也被称为 “三次握手”
- 当TCP连接建立后,两个应用进程就可以发送数据了。
- 应用程序将要发送的数据通过Socket传递给TCP,TCP将数据引导到该连接的发送缓存,发送缓存大小是在三次握手的过程中确定的;之后TCP将时不时从该缓存中拿出数据进行发送,
- 一个有趣的事情是,TCP规范中没有规定TCP应该在何时 发送缓存里的数据,只是描述为 “TCP应该在它方便的时候以报文段的形式发送数据” ;
- TCP每次可以从缓存中发送的最大数据长度称为 MSS(Maximum Segment Size)(最大报文段(说是报文段但是按概念来讲是报文)长度)。
- 一般来说,MSS+TCP/IP首部的长度要小于等于链路的MTU(即链路层最大帧长度Maximum Transport Unit)而以太网和PPP的MTU都等于1500字节,TCP/IP的首部通常为40字节,所以MSS一般来说为1460字节。
- 注意: MSS指的是报文段中应用层数据最大长度,而不是包括TCP首部的报文段长度。
- TCP为每块客户数据加上TCP首部后就形成了一个个TCP报文段;这些TCP报文段被交给网络层,网络层将分别封装在网络IP数据报中。然后这些IP数据包被发送到网络中;当TCP在另一端接收到一个报文段,便进入了TCP连接的接收缓存中,等待被应用程序读取。
- TCP连接的每一端都有发送和接收缓存
- TCP报文段结构:
- TCP报文段==TCP首部+数据字段组成;
- 其中数据字段来自应用层,其长度不能大于MSS;
- 首部的常规长度为20字节,但是值得注意的是,TCP首部是可变长的;TCP首部是以32比特为单位组织的,其结构组成如下图:
- 源端口号和目的端口号:
- 这两个数据用于TCP的多路复用和多路分解;分别为16位;
- 序号:
- 该数据被用于实现可靠数据传输之按序到达,在一个TCP连接中,算是一个报文段的id,
- 同时该id还指示了其所承载的数据的位置信息;占32位;
- 该数据被用于实现可靠数据传输之按序到达,在一个TCP连接中,算是一个报文段的id,
- 确认(序)号:
- 该数据表示接收方已经正确接收的报文段的序号,在流水线的差错恢复方案里,不同的恢复策略有不同的意义:
- 回退N步里:当发送方接收到对K的确认号时,表示所有序号小于K的报文段均已到达;
- 选择重传里:则仅表示序号为K的报文段被正确接收;
- 该数据表示接收方已经正确接收的报文段的序号,在流水线的差错恢复方案里,不同的恢复策略有不同的意义:
- 4比特的首部长度字段:
- 该字段指示了以32比特的字位单位的TCP首部长度。由于TCP选项字段的原因,TCP首部的长度是可变的。(该选项字段位空,所以TCP首部的典型长度是20字节)
- 可选与变长的预选字段
- 该字段用于在发送方和接收方之间协商MSS的大小,在高速网络环境下,也可用于调节窗口大小
- 窗口大小字段: 占16比特。此字段用来进行流量控制。单位为字节数,这个值是本机期望一次接收的字节数。
- TCP校验和字段: 占16比特。对整个TCP报文段,即TCP头部和TCP数据进行校验和计算,并由目标端进行验证。
- 紧急指针字段: 占16比特。它是一个偏移量,和序号字段中的值相加表示紧急数据最后一个字节的序号。
- 选项字段: 占32比特。可能包括”窗口扩大因子”、”时间戳”等选项。
- 6比特的标记字段
- ACK位(确认序号有效): 表示确认号字段的里的值是否有效,如果ACK被置位,那么该报文段就对确认号所指示的报文段进行了确认;
- RST、SYN和FIN位用于TCP的连接和拆除;
- RST:为1时,重建连接。
- SYN:为1时,同步程序,发起一个连接。
- FIN:为1时,发送端完成任务,释放一个连接。
- PSH被置位时,指示接收方应该立即将数据交给上层;
- URG(紧急指针(urgent pointer)有效): 被置位时表示报文段里存在着发送端的上层实体置为"紧急"的数据;紧急数据的最后一个字节由16位紧急指针指出。当紧急数据存在并且给出了指向紧急数据尾指针时,TCP必须通知接收端的上层实体(在实践中PSH,URG和紧急数据指针并没有使用,所以我们说为6比特);
- CWR,ECE: 在明确拥塞通告中使用了。
- 序号和确认号
- TCP报文段中两个重要的字段是确认号和序号;这两个字段是TCP实现可靠数据传输的重要部分;
- TCP将数据看作是一个无结构、有序的字节流;
- 值得注意的是,TCP的序号是基于传输的字节流之上,而不是报文段的序列之上;**因此,一个报文段的序号是该报文段首字节的字节流编码。**也就是说,来自应用层的数据被TCP包装在多个报文段中,其中第2个报文段的序列号不是2,而是1000,如果MSS为1000。
- 关于确认号,发送方充进报文段的确认号是发送方期望从接收方收到的下一字节的序号。
- 比如说,主机A已经收到了从主机B传来的编号为0~535的所有字节,同时主机A打算发送一个报文段给主机B,主机A等待主机B的数据流中字节536zhi后的所有字节。所以主机A就会在他发送gei主机B的报文段的确认号字段中填上536.
- TCP采用一种累计确认的方法
- 当接收方发来的报文段失序到达时,接收方怎么办呢?
- 接收方立即丢弃失序报文段
- 接收方保留失序的字节,并等待缺少的字节以填补该间隔
- 一条TCP连接可以采取任意数字作为初始序号,这样可以减少将那些残存在网络中的报文段误认为是新建连接的报文段(新旧连接恰巧采用了相同端口)
- 总体来说,一个报文段的序号就是该报文段数据字段首字节的序号;确认号就是接受主机正在等待接收的数据的下一个字节序号;值得注意的是,服务端对接收端发来的报文段的确认被装载到一个从服务端发往到接收端的报文段中,这种确认被称为 “捎带”
- 往返时间的估计与超时
- 问题: 时间间隔到底该设置多大呢?刚开始如何估计往返时间呢?是否应该为所有的未确认的报文各设一个定时器呢?
- 问:时间间隔应该设置多久呢?
- 答:指数加权移动平均:Sample RTT就是从某报文段发出到收到对该报文段的确认之间的时间量。大多数TCP的实现是在某个时刻做一个Sample RTT测试。TCP并不为已经重发的报文段做Sample RTT测试,它只为传输一次的报文段测量Sample RTT。
- Estimated RTT(新的)=(1-a)Estimated RTT(老的)+a*Sample RTT
- a一般取为0.125
- Sample RTT 新的测量的样本值
- 接着答:除了估计RTT外,计算RTT的变化也是you价值的的,
- DevRTT =(1-b)DevRTT+b|Sample RTT-Estimated RTT
- 其中b的推荐值为0.25;当Sample RTT变化较大的时候,DevRTT的值较大,当Sample RTT变化较小的时候,DevRTT就较小;
- 问:我们怎么进一步知道TCP超时间隔应该用什么呢?
- 答:能比Estimated RTT(新的)大,但是不要打太多,不然会导致报文丢失,TCP不能很快的重传该报文段,导致数据传输时延大。具体大多少,我们通过
RTT的变化DevRTT来判断,公式如下:
Timeout Interval=Estimated RTT+4*Dev RTT; - 当出现超时后,TimeOutInteval值将加倍。不管怎么样,一旦报文段收到并更新Estimated RTT后,TimeInteval就又用上值计算了
- TCP连接
-
可靠的数据传输
-
IP协议提供的是尽力而为的服务:不保证数据不丢失、不保证数据按序到达、不保证数据到达没有损坏,TCP协议在IP协议之上,提供可靠数据传输,从而保证一个进程从其相关联的缓存中读取的数据和另一端进程发送的数据是一致(无损坏、无间隙、非冗余、按序)的数据流;
-
(数据不丢失)TCP使用超时重传和冗余确认技术来处理超时、丢失等情况;
- TCP 发送方有三个与发送和重传有关的事件:
- 从上层应用程序接收数据
- 定时器超时(过期时间是Timeout Interval)
- 收到 ACK(这里也是对累计确认的一种解释)
- 当收到一个来自接收方的确认报文段(ACK)(一个包含了有效ACK字段值的报文段)。当该事件发生,TCP将AC的值y与它的变量sendBase(sendBase就是最早发送却未被确认的字节的序号)进行比较。当TCP采用累计确认,所以y确认了字节编号在y之前的所有字段都已经被收到。这时 ,当y>sendBase,则该ACK是在确认一个或多个先前未被确认的报文段。因此发送方更新它的sendBase变量;如果当前还有未被确认的报文段,定时器充新启动 。
- 当收到一个来自接收方的确认报文段(ACK)(一个包含了有效ACK字段值的报文段)。当该事件发生,TCP将AC的值y与它的变量sendBase(sendBase就是最早发送却未被确认的字节的序号)进行比较。当TCP采用累计确认,所以y确认了字节编号在y之前的所有字段都已经被收到。这时 ,当y>sendBase,则该ACK是在确认一个或多个先前未被确认的报文段。因此发送方更新它的sendBase变量;如果当前还有未被确认的报文段,定时器充新启动 。
- TCP 发送方有三个与发送和重传有关的事件:
-
(数据按序到达) 使用确认、序号等技术来保证按序到达;
-
(数据到达但没有损坏) 使用校验和来检验是否报文段在传输过程中是否发生了错误;
-
通过三种情况我们进一步理解TCP协议
-
超时时间加倍:
- 在大多数TCP实现中,当发生超时事件时,超时时间并不是从Estimated RTT和Dev RTT推算出来而是直接将超时时间设置为原来的两倍;然而,每当定时器在另两个事件(收到ACK和接收到上层应用数据)发生时,新的超时时间将由上面提到的两个值计算出来;实际上,这是一种形式受限的拥塞控制
-
快速重传:
- 响应超时事件,然后重传尚未收到确认的报文段,但是,当超时时间过长的时候,会显著增加端到端的延迟;一种可行的方法是对冗余ACK的的检测;在理解冗余ACK之前,需要先看一下接收方为什么会发送冗余ACK。接收方接收到某个报文段时,会检查该报文段是否是按序到达,如果不是,那么接收端会发送对已经收到的最后一个连续报文段的确认,所以如果发送方收到冗余ACK,说明有多个报文段到达了接收端,但不是接收端所期望的(失序)——这意味着,很有可能发生了丢失。所以发送方可以在定时器过时之前快速重传所丢失的报文段
- 怎样判断可以快速重传?
-
是回退N步还是选择重传
- 首先,我们需要明白的是,TCP采用了累计确认的机制,
- 也就说,如果接收方正确接收了某一失序到达的分组,那么接收方发送的ACK将是对最后接收的按序到达的分组的确认,而不是对刚刚接收的分组的确认;(从这一点看起来像GBN风格)
- 当然,许多TCP实现都会缓存失序的分组(这又是和GBN的区别);
- 那么问题来了,发生超时事件后,GBN将重传所有待确认的分组,而TCP重传丢失的分组,甚至如果收到了比丢失的分组序号还要大的ACK都不需要重传(这又是和GBN的区别);
对TCP提出的一种修改意见是所谓的选择确认——即接收方对失序到达的分组也会确认,当该机制和重传机制相结合使得TCP更像选择重传,于是TCP的差错恢复协议最好被分类为GBN和SR协议的混合体
-
流量控制(引用别人BLOG)
- 流量控制是一个速度匹配服务:TCP连接的发送方和接收方都各自维护一个缓存,因此两者的数据交换应该在一个合理的速度范围内:不让对方发生数据溢出;TCP为它的应用程序提供了这种服务:流量控制服务。虽然流量控制和拥塞控制所采取的动作非常相似,但是它们的目的很明显并不同。在接下来的讨论中,我们将假设TCP是这样实现的,即TCP接收方丢弃失序到达的报文段
在TCP首部中有一个窗口大小字段,TCP连接的双方通过该字段来向对方表明自己的窗口大小,即缓存空间的大小;同样,在TCP连接的两端,各自维护着相关的变量:last Sent、last Acked;在发送方,这两个变量之间的分组就是已经发送但是尚未确认的分组;而在接收方,last Read表示应用进程下一次读取的数据,last Revd表示最后纳入缓存的报文段编号(注意,我们讨论的前提是TCP会将失序到达的报文段丢弃哦~);通过这些变量以及报文段首部中窗口大小字段,我们就可以对发送速度做一些控制:在发送方last Sent-last Acked应该小于等于接收方的窗口大小;在接收端A=last Received-last Read就是已经使用的空间大小,所以窗口大小=buffer-A;
对了,还有一个问题就是,如果接收方的窗口大小为0,那么发送端该如何处理呢?一个需要注意的事实是,接收方在没有ACK或者数据要向发送端发送的时候,是不会通知发送方其窗口大小已经改变,即如果应用程序读取了缓存中的数据,发送方是不会知道的,除非它向接收方发送了数据,而发送方对其进行了确认;实际上,发送方也是这么做的!当接收到窗口大小为0的报文段后,发送方会向接收方间隔发送只有一个字节的数据。
- 流量控制是一个速度匹配服务:TCP连接的发送方和接收方都各自维护一个缓存,因此两者的数据交换应该在一个合理的速度范围内:不让对方发生数据溢出;TCP为它的应用程序提供了这种服务:流量控制服务。虽然流量控制和拥塞控制所采取的动作非常相似,但是它们的目的很明显并不同。在接下来的讨论中,我们将假设TCP是这样实现的,即TCP接收方丢弃失序到达的报文段
-
2021-05-20 《计算机网络(自顶向下方法)》第3章——总结上(运输层)
最新推荐文章于 2023-04-26 17:06:09 发布