前文回顾:第二章:应用层
目录
📚概述和运输层服务
🐇运输层和网络层的关系
🐇因特网传输概述
📚多路复用和多路分解
🐇无连接的多路复用与多路分解
🐇面向连接的多路复用与多路连接
📚无连接传输:UDP
🐇UDP报文结构
📚可靠数据传输原理
🐇构造可靠信道的可靠数据传输
🥕经完全可靠信道的可靠数据传输:rdt 1.0
🥕经具有比特差错信道的可靠数据传输:rdt 2.0 、rdt 2.1、rdt 2.2
🥕经具有比特差错的丢包信道的可靠数据传输:rdt3.0
🐇流水线可靠数据传输协议
🐇回退N步(GBN)
🐇选择重传(SR)
🐇可靠数据传输机制及其用途总结
📚面向连接的TCP
🐇TCP连接
🐇TCP报文段结构
🐇往返时间的估计与超时
🐇可靠数据传输
🥕一些有趣的情况
🥕超时时间加倍
🥕快速重传
🥕是回退N步还是选择重传
🐇流量控制
🐇TCP连接管理
🥕TCP连接的建立——“三次握手”
🥕TCP连接的释放——“四次挥手”
📚拥塞控制原理
🐇拥塞原因与代价
🐇拥塞控制方法
📚TCP拥塞控制原理
🐇慢启动
🐇拥塞避免
🐇快速恢复
传输层(运输层)位于应用层和网络层之间,是分层的网络体系结构中重要的部分,该层为运行在不同主机上的应用进程提供直接的通信服务起着至关重要的作用。
- 我们将从讨论运输层和网络层的关系开始,即将网络层的在两个端系统之间的交付服务扩展到运行在两个不同端系统上的应用层进程之间的交付服务。
- 然后我们探讨两个实体怎样才能在一种会丢失或损坏数据的媒体上可靠地通信。并说明这些原理是如何体现在因特网面向连接的运输协议TCP中的。
- 接下来我们讨论拥塞控制问题,即控制运输层实体的传输速率以避免网络中的拥塞或从拥塞中恢复过来。
📚概述和运输层服务
- 运输层协议为运行在不同主机上的应用进程之间提供逻辑通信功能;
- 应用进程使用运输层提供的逻辑通信功能而无需考虑实现通信的物理基础设施的细节;
- 运输层协议是在端系统中而不是在路由器中实现的。
- 运输层接收来自应用层的报文并通过添加运输层首部以生成运输层报文段。
- 在生成过程中可能会对来自应用层的报文加以分割;然后在发送端系统中,运输层会将这些报文段交给网络层;网络层将其封装成网络层分组,也被称为数据报,然后向目的地发送。
- 网络路由器仅作用于该数据报的网络层字段,路由器不会检查封装在数据报中的传输层报文段的字段;在接收端,网络层从数据报中抽取传输层报文段,并将其交给传输层,传输层接收到报文段后,使该报文段中的数据被接收进程所使用。
- 网络应用可以使用多种传输层协议,因特网有两种传输层协议,即TCP和UDP,不同的传输层协议提供不同的运输层服务 。
🐇运输层和网络层的关系
- 网络层提供了主机之间的逻辑通信,运输层为运行在不同主机上的进程之间提供了逻辑通信。
- 运输层协议只工作在端系统中,举个例子——
- 邮政服务把信件从一家送往另一家。每个家庭里,Ann和Bill为堂兄弟姐妹之间送信,从汤兄弟姐妹的角度看,Ann和Bill就是邮件服务,尽管他们只是端到端交付过程的一部分(即端系统部分)。用这个例子进行类比:
网络层协议 | 邮政服务(包括邮车) |
运输层协议 | Ann和Bill |
主机(又称为端系统) | 家庭 |
进程 | 堂兄弟姐妹 |
应用层报文 | 信封上的字符 |
- 在端系统中,传输层协议将来自应用进程的报文移动到网络边缘即网络层,反过来也从网络层接收这些报文段;传输层对报文段如何在网络核心传输并不做干涉;事实上中间路由器既不处理也不识别传输层加载应用层报文上的任何信息。
- 运输层协议能提供的服务常常受制于底层网络层协议的服务类型,如果网络层协议无法为主机之间的通信提供时延和带宽保证的话,运输层协议也就无法为进程之间发送的应用程序报文提供时延或者带宽保证。然而即使底层网络协议不能在网络层提供响应的服务,运输层协议也能提供某些服务。例如,即使底层网络协议是不可靠的,运输协议也能为应用程序提供可抗的数据传输服务。
🐇因特网传输概述
- 因特网为应用层提供了截然不同的两种传输层协议:UDP(用户数据报协议)它提供一种不可靠、无连接的服务;另一种是TCP(传输控制协议),它提供可靠的,面向连接的服务;
- 运输层分组也被称为报文段;
- 简单了解一下因特网的网络层,网络层协议有一个名字即IP,即网际协议。IP为主机间提供逻辑通信,IP的服务模型为尽力而为交付服务。这意味着IP尽最大的努力在主机间交付报文段,但是不做任何保证。它不保证报文段的交付、不保证报文段按序交付、不保证报文段中数据的完整性,即IP提供一种不可靠的服务;
- 每台主机至少有一个网络层地址,即所谓的IP地址。在本篇博客中,我们只需要记住每台主机有一个IP地址。
- 在对IP服务模型有了初步了解后,我们总结一下UDP和TCP所提供的服务模型。UDP和TCP最基本的责任就是,将两个端系统间IP的交付服务扩展为运行在端系统上的两个进程之间的交付服务,这也被称为传输层的多路分解和多路复用;
- UDP和TCP通过在传输层首部添加差错检查字段来提供完整性检查。进程到进程之间的数据交付和差错检查是最低限度的两种传输层服务,也是UDP可以提供的仅有的两种服务。UDP和IP一样,也是不可靠服务;
- TCP提供额外的服务,首先它提供可靠数据传输。通过使用流量控制、序号、确认和定时器,TCP确保正确地、按序地将数据从发送进程交付给接收进程。这样,TCP就将两个端系统间的不可靠IP服务转换成进程间的可靠数据传输服务。
- 其次,TCP提供拥塞控制,拥塞控制与其说是一种提供给应用程序的服务,不如说是一种提供给整个网络的服务,因为整个网络都将因为拥塞控制而受益;不太严格地说,拥塞控制力求为每个通过一条拥塞网络的连接平等地共享共享网络链路带宽,从而避免一条TCP连接用过多的流量来淹没通信主机之间的链路和交换设备;拥塞控制是通过调节发送进网络的的流量速率来做得到;UDP不提供拥塞控制,使用UDP传输的应用程序可以根据需要以任意的速率发送数据。
📚多路复用和多路分解
有前面的介绍,我们可以知道,传输层将网络层提供的面向主机的逻辑通信扩充为面向不同应用进程的逻辑通信,并且这一过程称为多路复用和多路分解;值得注意的是,多路复用和多路分解是每个计算机网络都需要的。
- 一个进程有一个或多个套接字(socket),它相当于从网络向进程传递数据和从进程向网络传递数据的门户。实际上,传输层和应用程序进程之间通过套接字关联,这样通过Socket就可以区别同一主机上的不同应用进程,从而传输层提供服务变为可能。
- 将运输层报文段中的数据交付到正确的套接字的工作称为多路分解。
- 在源主机从不同套接字中收集数据块,并为每个数据块封装上首部信息(用于分解)从而生成报文段,然后将报文段传递到网络层,这些所有工作称为多路复用。
- 回顾之前的类比,当Bill从邮递员处收到一批信件,并通过查看收信人名字而将信件亲手交付给他的兄弟姐妹时,他执行的就是一个分解操作。当Ann从兄弟姐妹那里收集信件并将它们交给邮递员时,她执行的就是一个多路复用操作。
- 运输层多路复用的要求:①套接字有唯一标识符(即唯一的ID,被称为端口号);②每个报文段有特殊字段来指示该报文段所要交付到的套接字。如下图所示,这些特殊字段是源端口字段和目的端口字段。端口号是一个16比特的数,其大小在0~65545之间,其中0-1023属于周知端口号,它们为特定的Socket而拥有。
- 运输层如何实现分解服务:在主机上的每个套接字能够分配一个端口号,当报文段到达主机时,运输层检查报文段中的目的端口号,并将其定向到相应的套接字。然后报文段中的数据通过套接字进入其所连接的进程。
🐇无连接的多路复用与多路分解
- 在创建Socket的时候,是由传输层为之分配端口号;
- 一个UDP套接字是由一个目的IP地址和目的端口号即二元组来标志的;如果两个UDP报文段有不同的源IP地址或者源端口号,但是有相同的目的IP和目的端口号的话,它们将通过同一个Socket到达同一个应用程序 。
- 在A到B的报文段中,源端口号用作“返回地址”的一部分,即当B需要会发一个报文段给A时,B到A的报文段中的目的端口号便从A到B的报文段中的源端口号中取值。
🐇面向连接的多路复用与多路连接
- TCP协议中的套接字是通过一个四元组(源IP地址,源端口号,目的IP地址,目的端口号) 来标识的。因此,当一个TCP报文段从网络到达一台主机时,该主机使用全部4个值来将报文段定向到相应的套接字。
- 特别与UDP不同的是,两个具有不用源IP地址或源端口号的到达TCP报文段将被定向到两个不同的套接字。也就是说,两个具有不同源IP地址或者源端口号,但有相同的目的IP地址和目的端口号的TCP报文段将通过两个不同的套接字进入同一应用进程;
- 一个应用进程可以关联多个套接字,而一个套接字将只关联一个应用进程;常常,这样的对应关系是通过线程来实现的:一个进程有多个线程,而每个线程关联了一个套接字;
📚无连接传输:UDP
- 差错检查和进程到进程的数据交付是传输层协议必须提供的功能,事实上,UDP的确做到了这些,并且只做了这些。
- 它几乎没有对IP增强别的东西;因为在发送报文段之前,发送方和接收方的传输层实体之间没有握手,所以UDP也被称为无连接的;
- DNS是一个使用UDP的应用层协议例子;UDP在接收到来自Socket的数据时,UDP为该报文添加首部字段(源和目的端口号,以及其他两个小字段),然后将报文段交给网络层,网络层通过IP协议尽力地将该报文段交付,至于结果,尽力就好;当DNS客户端等待不到对该查询的响应时(有可能网络层将其丢失了)则会向其他Name Server发送查询请求,要么就通知应用程序它不能获得相应。
- 为什么TCP那么可靠,UDP那么佛系以至于不太靠谱,它还没被淘汰呢?
- 关于何时、发送什么数据的应用层控制更为精细:这是因为一旦应用程序将数据交给UDP,UDP就会打包将其发送给网络层,不会受到传输层的调节,这在一些实时应用中比较实用;当然,应用程序还可以通过UDP+自主开发一些功能的模式来扩展UDP。
- 无需建立连接:所以就不会引入额外的时延。这也可能是DNS使用UDP而不是TCP的主要原因,如果使用TCP的话,DNS服务将会慢很多;HTTP使用TCP的主要原因是对TCP的可靠性的依赖超过对速度的要求;
- 无需维护连接状态:TCP为了实现可靠数据传输和拥塞控制需要在端系统中维护一些参数,这些参数包括:接收和发送的缓存、拥塞控制参数、确认号和序号;这些参数信息都是必须的;而UDP因为不建立连接,所以自然也就不需要维护这些状态,这就减少了时空开销;
- 分组首部更小:TCP有20字节的首部开销,而UDP只有8字节。
- 电子邮件、远程终端访问、Web、文件传输使用了TCP作为其传输层协议;
- 远程文件服务器、网络管理、路由选择协议和名称转换(DNS)通常使用UDP作为其传输层协议,因为这些应用即便在网络处于拥塞的情况下仍要工作,所以UDP更为合适;
- 这些应用两个都有使用:流式多媒体、因特网电话等多媒体应用;这些应用对实时性的要求较高同时对可靠性的要求又不是很高,所以既可以使用UDP也可以使用TCP协议。
- 不过在UDP之上运行多媒体应用是有争议的,因为UDP没有拥塞控制协议,所以其对网络有很大的威胁性:大量的UDP流量将使网络过度拥塞而造成TCP连接几乎无法传输数据,并且因为网络拥塞,所以应用又有着较高的丢包率,而因为丢包率UDP很有可能继续发送数据,由此使得网络效率低下。
- 也有研究人员提出一些新的机制,使得所有数据源,包括UDP源执行自适应的拥塞控制来解决这一问题;
- 需要注意的是,使用UDP仍然可以实现可靠数据传输,只不过这一部分功能需要在应用程序中自主开发;将可靠性直接构建于应用程序中,将使其既可以可靠地传输数据又可以避免受制于TCP的拥塞控制(传输速率的控制)
🐇UDP报文结构
- UDP首部只有4个字段,每个字段占两字节,分别是源端口号、目的端口号、长度和校验和;
- 其中,长度表示包含首部在内的UDP报文段长度,以字节为单位;
- 校验和字段用来计算报文段在传输的过程中是否出现了差错;
- 一种常见的校验和的计算方法是:发送方将前三个字段做按位加运算,然后将其取反作为校验和;然后接收方对所有四个字段(每个字段16位)进行求和,如果没有出现差错,则最后的结果全是1,否则就表明出现了错误;
- 出现错误的原因可能有:传输链路上数据受到干扰、数据存储在中间路由器的时候,出现了错误。
- UDP作为传输层协议,提供的差错检测功能很有可能和底层协议提供的相似功能产生冗余,但是这是必须的。
- 因为不能保证源和目的地之间所有链路都提供差错检测功能,即便数据在链路上正确传输,也无法保证其在中间路由器的内存中不发生错误。
- 所以要实现端到端的差错检测,就必须在传输层协议中实现该功能;这一原则在系统设计中被称为端到端原则:“因为某一功能必须在端到端实现,与在较高层次提供这些功能的代价相比,在较低层次上设置的功能可能是冗余的,或者根本是没有用的”
- 因为假定IP是可以运行在任何第二层协议之上的,运输层提供差错检测作为一种保险措施是非常有用的。
- UDP可以检测差错,但是无法恢复差错,能做的除了将其丢弃外,便是将其交给应用程序然后给出警告。
📚可靠数据传输原理
可靠数据传输为上层实体提供的服务抽象是:数据可以通过一套可靠的信道进行传输。借助于可靠信道,传输数据就不会受到损坏或者丢失,并且所有数据都可以按照其发送顺序进行交付。而这正是TCP向调用它的应用所提供的服务模型 。
🐇构造可靠信道的可靠数据传输
🥕经完全可靠信道的可靠数据传输:rdt 1.0
- 最简单的情况,底层信号完全可靠,然而这在实际中不能实现 。
🥕经具有比特差错信道的可靠数据传输:rdt 2.0 、rdt 2.1、rdt 2.2
- 假设所有发送的分组都可以按其发送顺序被接收。在通常情况下,报文接收者在听到、理解并记下每句话后可能会说“OK”。如果报文接收者听到一句含糊不清的话时,他可能要求你重复那句容易误解的话。这种口述报文协议使用了肯定确认(ACK)和否定确认(NAK)。
- 基于重传机制的可靠数据传输协议称为自动重传请求协议(ARQ)。
- ARQ协议中还需要另外三种协议功能来处理存在比特差错的情况:差错检测,接收方反馈,重传。
- rdt2.0的发送端每发送一个分组需要等待接收端的确认信号,这种协议被称为停等协议。即发送方将不会发送一块新数据,除非发送方确信接收方已正确接收当前分组。
- 但分组到达时,接收方要么回答一个ACK,要么回答一个NAK,这取决于收到的分组是否受损。rdt2.0的缺陷在于,如果一个ACK或NAK分组受损,发送方无法知道接收方是否正确接收了上一块发送的数据。
考虑ACK和NAK受损的两个可能性 :
- 增加足够的校验和比特。
- 当接受到模糊不清的ACK和NAK分组时,只需要重传当前数据分组。这引入了冗余分组。
- 冗余分组的根本困难在于接收方不知道它上次所发送的ACK和NAK是否被发送方正确接收到。因此它无法事先知道接收到的分组是新的还是一次重传。
- 解决这个新问题的一个简单的方法就是在数据分组中添加一个字段,让发送方对其数据分组编号,即将发送数据分组的序号放在该字段。于是,接收方只需要检查序号即可确定收到的分组是否一次重传。对于停等协议这种简单的情况,1 比特的序号就足够了。
- 如果不发送NAK,而是对上次正确接收的分组发送一个ACK,我们也能实现同样的效果。
- 发送方接收到对一个分组的两个ACK(冗余ACK)后,就知道接收方没有正确接收到跟在确认两次的分组后面的分组。
- rdt 2.2 是在有比特差错信道上实现的一个无NAK的可靠数据传输协议。
- rdt 2.1和rdt 2.2的区别在于,接收方此时必须包括由一个ACK报文所确认的分组序号。
🥕经具有比特差错的丢包信道的可靠数据传输:rdt3.0
- 在 rdt 3.0 中,丢包的问题让发送方解决。不管是发送的分组丢失,还是接收方返回的确认分组丢失,只要在经过一定的时延后,让发送方重发该分组即可。
- 由此产生的冗余数据分组则由接收方通过序号处理。为了实现基于时间的重传机制,需要一个倒计时定时器。
- 因为分组序号在 0 和 1 之间交替,因此 rdt 3.0 有时被称为比特交替协议。
🐇流水线可靠数据传输协议
rdt 3.0 是一个功能正确的协议,但是由于它是一个停等协议,大部分的时间都浪费在等待确认上面,所以性能不好。 解决这种特殊性能问题的一个简单的方法是:不使用停等方式运行,允许发送方发送多个分组而无需等待确认。这种技术被称为流水线。
要使用流水线技术,则须 :
- 增加序号范围。因为要传送多个分组,而每个传输中的分组必须有一个单独的序号。
- 协议的发送方和接收方两端必须能缓存多个分组。发送方至少得能缓存那些已发送但未确认的分组,而接收方或许也需要缓存那些已经正确接收的分组。
- 所需序号的范围和对缓冲的要求取决于数据传输协议如何处理丢失、损坏及延时过大的分组。
流水线的差错恢复有两种基本方法 :回退N步、选择重传。
🐇回退N步(GBN)
- 在回退N步协议中,允许发送方发送多个分组而不需等待确认,但它也受限于在流水线中未确认的分组数不能超过某个最大允许数N。
- 那些已被发送但还未被确认的分组的许可序号范围可以被看成是一个在序号范围内长度为N的窗口。随着协议的进行,该窗口在序号空间内向前滑动。因此,N常被称为窗口长度,GBN协议也常被称为滑动窗口协议。
GBN发送方必须响应三种类型的事件:
- 上层的调用:当上层调用rdt_send()时,发送方首先检查发送窗口是否已满,即是否有N个已发送但未被确认的分组。如果窗口未满,则产生一个分组并将其发送,并相应地更新变量。如果窗口已满,发送方只需将数据返回上层,隐晦地指示上层该窗口已满,稍后再试。
- 收到一个ACK:回退N步策略对序号为n的分组采取累积确认的方式,即当收到序号为n的ACK时,表明序号小于等于n的分组全部到位;
- 超时事件:如果发生超时事件,那么发送方会重发所有已发送但是未确认的分组,即分组号在base和next sequence-1之间的所有分组,这也是为什么叫“回退N步”。如果收到一个ACK,则定时器会重行启动;如果没有待确认的分组,定时器将被终止;
在GBN中,接收方的动作也很简单:
- 如果到达分组的序号为n且该分组是按序(即上次交付给上层的数据时序号为n-1的分组)到达,则接收方为分组n发送一个ACK,并将该分组中的数据部分交付到上层。在所有其它情况下,接收方丢弃该分组,并为最近按序接收的分组重新发送ACK。
- 丢弃一个正确接收(但失序)分组可能会导致更多的重传 ,但优点是接收缓存简单即接收方不需要缓存任何失序分组。
🐇选择重传(SR)
- GBN存在性能问题:当窗口和带宽的时延都较大时,单个分组的差错可能会引起GBN重传大量的分组,然后许多本来不用重传的分组会充斥在信道中,造成资源浪费;
- 选择重传就是让发送方仅重传那些丢失和受损的分组而避免不必要的重传 。
- 参考学习视频:可靠传输的实现机制—选择重传协议,指路4:40看SR实例。
小结:
🐇可靠数据传输机制及其用途总结
- 一个可靠数据传输协议,将要面对以下问题:分组丢失、分组损坏到达、分组乱序到达。
- 总结可靠传输需要的技术:检验和、序号、定时器、确定、否定确认及窗口、流水线。
📚面向连接的TCP
🐇TCP连接
- TCP协议之所以被称为是面向连接的协议,是因为在一个应用进程可以向另一个应用进程发送数据前,这两个进程将首先“握手”,即它们必须相互发送某些预备报文段,以建立确保数据传输的参数。
- 作为TCP连接建立的一部分,连接的双方都将初始化与TCP连接相关的许多TCP状态变量。
- TCP的连接,并不是一条像电路交换网络中端到端的TDM或FDM电路,相反,该连接是一条逻辑链接,其共同状态仅保留在两个通信端系统的TCP程序中。
- 事实上,中间路由器对TCP连接完全视而不见,它们看到的是数据报,而不是连接。
- TCP提供全双工服务,并且是点对点的(即在单个发送方与单个接收方之间的连接),数据从A到B的同时,也能从B到A;TCP协议无法提供“多播”服务,一条TCP连接只关联一个发送方和接收方(当然,发送方也是接收方);
关于TCP的连接:
- 发起连接的进程被称为客户进程,而另一个进程被称为服务器进程。
- 客户首先发送一个特殊的TCP报文段,服务器用另一个特殊的TCP报文段来响应,最后,客户再用第三个特殊报文段作为响应。前两个报文段不承载“有效载荷”,也就是不包含应用层数据;而第三个报文段可以承载有效载荷。由于在这两台主机之间发送了3个报文段,所以这种连接建立过程常被称为三次握手。
- 一旦建立起一条TCP连接,两个应用进程之间就可以相互发送数据了。
- 应用程序将要发送的数据通过套接字传递给TCP,TCP将数据引导到该连接的发送缓存,发送缓存大小是在三次握手的过程中确定的,之后TCP将时不时从该缓存中拿出数据进行发送。
- 有趣的是,TCP规范中没有规定TCP应该在何时发送缓存里的数据,描述为“TCP应该在它方便的时候以报文段的形式发送数据”。
- TCP可从缓存中取出并放入报文段中的数据数量受限于最大报文段长度(MSS,指的是报文段中应用层数据最大长度 )。一般来说,MSS+TCP/IP首部的长度要小于等于链路的链路层最大帧长度(MTU)。而以太网和PPP的MTU都等于1500字节,TCP/IP的首部通常为40字节,所以MSS一般来说为1460字节。
- TCP为每块客户数据配上一个TCP首部,从而形成了多个TCP报文段;这些TCP报文段被交给网络层,然后被发送到网络中;当TCP报文段到达接收端时,便进入了接收端的缓存,等待被应用程序读取。
- TCP连接的每一端都有发送和接收缓存。
🐇TCP报文段结构
- TCP报文段结构,从整体上来说由首部+数据字段组成;其中数据字段来自应用层,包含一块应用数据,其长度不能大于MSS;首部的常规长度为20字节,但是值得注意的是,TCP首部是可变长的;TCP首部是以32比特为单位组织的,其结构组成如下图:
- 和UDP一样,TCP首部包括源端口号和目的端口号,这两个数据用于TCP多路复用和多路分解,均为16位。也包括校验和字段,用来计算报文段在传输的过程中是否出现了差错;
- 序号:该数据被用于实现可靠数据传输中的按序到达,在一个TCP连接中,算是一个报文段的id,同时该id还指示了其所承载的数据的位置信息,占32位;
- 确认号:该数据表示接收方已经正确接收的报文段的序号,在流水线的差错恢复方案里,不同的恢复策略有不同的意义:回退N步里,当发送方接收到K的确认号时,表示所有序号小于K的报文段均已到达;而在选择重传里,则仅表示序号为K的报文段被正确接收,占32位;
- 接收窗口:16位,用于流量控制,指示接收方愿意接受的字节数量。
- 首部长度:该字段指示了以32比特的字为单位的TCP首部长度,它占4比特。TCP的首部是可变长的,所以该字段表示报文段的首部长度,也揭示了应用数据的开始位置。
- 选项:该字段用于在发送方和接收方之间协商MSS的大小,在高速网络环境下,也可用于调节窗口大小;
- 6比特的标志字段
- ACK位表示确认号字段的里的值是否有效,如果ACK被置位,那么该报文段就对确认号所指示的报文段进行了确认;
- RST、SYN和FIN位用于TCP的连接和拆除;
- PSH被置位时,指示接收方应该立即将数据交给上层;
- URG被置位时表示报文段里存在着发送端的上层实体置为紧急的数据;紧急数据的最后一个字节由16位紧急数据指针指出。当紧急数据存在并且给出了指向紧急数据尾指针时,TCP必须通知接收端的上层实体;
-
然而,实际上,PSH、URG和紧急数据指针在实践中并没有被使用,考虑到完整性,这里作全解释。
- TCP报文段中两个重要的字段是确认号和序号,这两个字段是TCP实现可靠数据传输的重要部分。TCP将数据看作是一个无结构、有序的字节流。
- 值得注意的是,TCP的序号是基于传输的字节流之上,而不是报文段的序列之上。也就是说,来自应用层的数据被TCP包装在多个报文段中,其中第2个报文段的序列号不是2,而是1001,如果MSS为1000。
- 关于确认号,如果采取回退N步策略,那么TCP采用一种累计确认的方法,前面已经提到过,这里就不赘述。
- 一条TCP连接可以采取任意数字作为初始序号,这样可以减少将那些残存在网络中的报文段误认为是新建连接的报文段(它碰巧与旧链接使用了相同的端口号)
🐇往返时间的估计与超时
- TCP使用超时重传机制来处理报文段的问题,虽然这在概念上很简单,但如何设置超时时间取决于网络的状态,所以需要做的是估计网络的状态。
- 参考学习视频:TCP超时重传时间的选择,指路11:20看计算重传时间实例。
- TCP使用一种Sample RTT的方法来估计RTT。Sample RTT就是从某报文段发出到收到对该报文段的确认之间的时间量。
- 大多数TCP的实现是在某个时刻做一个Sample RTT测试。TCP并不为已经重发的报文段做Sample RTT测试,它只为传输一次的报文段测量Sample RTT。
- TCP一般通过EstimatedRTT = (1-a)·EstimatedRTT + a * SampleRTT来计算因路由器的拥塞和端系统负载变化所导致变化的RTT。a一般取1/8。因为Estimated RTT表示最近的网络状况,所以其理应得到较大的权值,越近的样本越能更好地反映网络当前拥塞状况。这种平均也被称为指数加权移动平均(EWMA)。
- 除了估计RTT外,测量RTT的变化也是有价值的的,DevRTT = (1-β)·DevRTT + β· |Sample RTT - Estimated RTT|;其中β的推荐值为0.25;当Sample RTT变化较大的时候,DevRTT的值较大,当Sample RTT变化较小的时候,DevRTT就较小。
- TCP考虑超时时间,该时间应该略大于测量的RTT。不易过小——容易引起不必要的重传,也不易过大——网络对于报文段丢失情况的反应就会变慢。最后TCP采用了如下计算方式:TimeoutInterval = EstimatedRTT + 4 · DevRTT。
🐇可靠数据传输
- IP协议提供不可靠的、尽力而为的服务,TCP协议在IP协议之上,提供可靠数据传输,从而保证一个进程从其相关联的缓存中读取的数据和另一端进程发送的数据是一致的。
- TCP使用超时重传和冗余确认技术来处理超时、丢失等情况;使用确认、序号等技术来保证按序到达;使用校验和来检验是否报文段在传输过程中是否发生了错误;
在TCP发送方有3个与发送和重传有关的主要事件:
- 从上层应用程序接收数据:TCP从应用程序接收数据,将数据封装在一个报文段中,并把该报文段交给IP。
- 定时器超时:TCP通过重传引起超时的报文段来响应超时时间,然后TCP重启定时器。
- 收到ACK:当事件发生时,TCP将ACK的值y与它的变量SendBase进行比较。
🥕一些有趣的情况
🥕超时时间加倍
- 推荐的初始TimeoutInterval值为1秒。在大多数TCP实现中,当发生超时事件时,超时时间并不是由Estimated RTT和Dev RTT推算出来,而是直接将超时时间设置为原来的两倍;
- 然而,每当定时器在另两个事件(收到ACK和接收到上层应用数据)发生时,新的超时时间将由上面提到的两个值计算出来;实际上,这是一种形式受限的拥塞控制 。
🥕快速重传
- 响应超时事件,然后重传尚未收到确认的报文段,但是,当超时时间过长的时候,会显著增加端到端的延迟;
- 一种可行的方法是对冗余ACK的的检测。冗余ACK就是再次确认某个报文段的ACK,而发送方先前已经收到对该报文段的确认。
- 在理解冗余ACK之前,需要先看一下接收方为什么会发送冗余ACK。接收方接收到某个报文段时,会检查该报文段是否是按序到达,如果不是,那么接收端会发送对已经收到的最后一个连续报文段的确认,所以如果发送方收到冗余ACK,说明有多个报文段到达了接收端,但不是接收端所期望的——这意味着,很有可能发生了丢失。
- 一旦收到3个冗余ACK,TCP就执行快速重传,即在该报文段的定时器过期之前重传丢失的报文段。
🥕是回退N步还是选择重传
- 首先,TCP采用了累计确认的机制,也就说,如果接收方正确接收了某一失序到达的分组,那么接收方发送的ACK将是对最后接收的按序到达的分组的确认,而不是对刚刚接收的分组的确认。
- 当然,许多TCP实现都会缓存失序的分组;那么问题来了,发生超时事件后,GBN将重传所有待确认的分组,而不是丢失的分组,而选择重传会好很多。
- 对TCP提出的一种修改意见是所谓的选择确认——即接收方对失序到达的分组也会确认,当该机制和重传机制相结合使得TCP更像选择重传,于是TCP的差错恢复协议最好被分类为GBN和SR协议的混合体。
🐇流量控制
参考学习视频:TCP的流量控制
- 流量控制是一个速度匹配服务,即发送方的发送速率和接收方应用程序的读取速率相配:TCP连接的发送方和接收方都各自维护一个缓存,因此两者的数据交换应该在一个合理的速度范围内——不让对方发生数据溢出。
- TCP为它的应用程序提供了这种服务:流量控制服务。虽然流量控制和拥塞控制所采取的动作非常相似,但是它们的目的很明显并不同 。
- TCP通过让发送方维护一个称为接收窗口的变量来提供流量控制。通俗地说,接收窗口用于给发送方一个指示——该接收方还有多少可用的缓存空间。
- 对了,还有一个问题就是,如果接收方的窗口大小为0,那么发送端该如何处理呢?一个需要注意的事实是,接收方在没有ACK或者数据要向发送端发送的时候,是不会通知发送方其窗口大小已经改变,即如果应用程序读取了缓存中的数据,发送方是不会知道的,除非它向接收方发送了数据,而发送方对其进行了确认;实际上,发送方也是这么做的!当接收到窗口大小为0的报文段后,发送方会向接收方间隔发送只有一个字节的数据。
🐇TCP连接管理
参考学习视频:TCP的运输连接管理
🥕TCP连接的建立——“三次握手”
- TCP协议中,主动发起请求的一端称为客户端,被动连接的一端称为服务端。不管是客户端还是服务端,TCP连接建立完后都能发送和接收数据。
- 起初,服务器和客户端都为CLOSED状态。在通信开始前,双方都得创建各自的传输控制块(TCB)。 服务器创建完TCB后遍进入LISTEN状态,此时准备接收客户端发来的连接请求。
- 传输控制块里有TCP连接表、指向发送和接收缓存的指针、指向重传队列的指针、当前的发送和接收序号等等。
⭐第一次握手
- 客户端向服务端发送连接请求报文段。该报文段的头部中SYN=1,ACK=0,seq=x。请求发送后,客户端便进入SYN-SENT状态。
- SYN=1,ACK=0表示该报文段为连接请求报文。
- x为本次TCP通信的字节流的初始序号。 TCP规定:SYN=1的报文段不能有数据部分,但要消耗掉一个序号。
⭐第二次握手
- 服务端收到请求后,如果同意,则会发送一个应答:SYN=1,ACK=1,seq=y,ack=x+1。 该应答发送完成后便进入SYN-RCVD状态。
- SYN=1,ACK=1表示该报文段为连接同意的应答报文。
- seq=y表示服务端作为发送者时,发送字节流的初始序号。
- ack=x+1表示服务端希望下一个数据报发送序号从x+1开始的字节。
⭐第三次握手
- 当客户端收到连接同意的应答后,还要向服务端发送一个确认报文段,表示:服务端发来的连接同意应答已经成功收到。
- 该报文段的头部为:ACK=1,seq=x+1,ack=y+1。 客户端发完这个报文段后便进入ESTABLISHED状态,服务端收到这个应答后也进入ESTABLISHED状态,此时连接的建立完成!
为什么还需要TCP确认报文段?
- 如上图所示,三次握手可以防止失效的连接请求报文段被服务端接收,从而产生错误。
- 失效的连接请求抵达了服务端,由于只有两次握手,服务端收到请求就会进入ESTABLISHED状态,等待发送数据或主动发送数据。但此时的客户端早已进入CLOSED状态,服务端将会一直等待下去,这样浪费服务端连接资源。
🥕TCP连接的释放——“四次挥手”
我们知道,TCP连接是双向的,因此在四次挥手中,前两次挥手用于断开一个方向的连接,后两次挥手用于断开另一方向的连接
⭐第一次挥手
- 若A认为数据发送完成,则它需要向B发送连接释放请求。该请求只有报文头,头中携带的主要参数为: FIN=1,seq=u。此时,A将进入FIN-WAIT-1状态。
- FIN=1表示该报文段是一个连接释放请求。
- seq=u,u-1是A向B发送的最后一个字节的序号。
⭐第二次挥手
- B收到连接释放请求后,会通知相应的应用程序,告诉它A向B这个方向的连接已经释放。此时B进入CLOSE-WAIT状态,并向A发送连接释放的应答,包含: ACK=1,seq=v,ack=u+1。
- ACK=1:除TCP连接请求报文段以外,TCP通信过程中所有数据报的ACK都为1,表示应答。
- seq=v,v-1是B向A发送的最后一个字节的序号。
- ack=u+1表示希望收到从第u+1个字节开始的报文段,并且已经成功接收了前u个字节。
- A收到该应答,进入FIN-WAIT-2状态,等待B发送连接释放请求。
- 第二次挥手完成后,A到B方向的连接已经释放,B不会再接收数据,A也不会再发送数据。但B到A方向的连接仍然存在,B可以继续向A发送数据。
⭐第三次挥手
- 当B向A发完所有数据后,向A发送连接释放请求。
- 请求头:FIN=1,ACK=1,seq=w,ack=u+1。B便进入LAST-ACK状态。
⭐第四次挥手
- A收到释放请求后,向B发送确认应答,包含:ACK=1,seq=u+1,ack=w+1。此时A进入TIME-WAIT状态。
- 该状态会持续2MSL时间,若该时间段内没有B的重发请求的话,就进入CLOSED状态,撤销TCB。当B收到确认应答后,也便进入CLOSED状态,撤销TCB。
为什么A要先进入TIME-WAIT状态,等待时间后才进入CLOSED状态?
- 为了保证B能收到A的确认应答。
- 若A发完确认应答后直接进入CLOSED状态,那么如果该应答丢失,B等待超时后就会重新发送连接释放请求,但此时A已经关闭了,不会作出任何响应,因此B永远无法正常关闭。
📚拥塞控制原理
🐇拥塞原因与代价
计算机网络拥塞的原因是因为网络中的分组太多,而链路带宽和路由器缓存容量都是有限的;
- 当分组的到达速率接近链路容量时,分组将经历巨大的排队时延。
- 发送方必须执行重传来补偿因为缓存溢出而丢弃的分组。
- 发送方遇到大时延时所进行的不必要重传会引起路由器利用其链路带宽来转发不必要的分组副本。
- 当一个分组沿着一条路径被丢弃时,每个上游路由器用于转发该分组到丢弃该分组而使用的传输容量最终被浪费掉了。
🐇拥塞控制方法
- 拥塞控制:作用于网络,防止过多的数据注入到网络,导致网络负载过大。
- 流量控制:作用于接收者,它是控制发送者的发送速度从而使接收者来得及接收。
总体来说,我们可以根据网络层是否为传输层拥塞控制提供了显式帮助来区分拥塞控制方法:端到端拥塞控制和网络辅助拥塞控制;
- 在端到端拥塞控制方法中,网络层并没有向传输层拥塞控制提供显式支持,即便网络中存在拥塞,端系统也必须通过对网络行为的观察(如分组丢失与时延)来判断。
- TCP必须通过端到端解决拥塞控制,因为IP层不会向端系统提供网络拥塞的反馈信息。
- TCP报文段的丢失(超时或者收到3次冗余确认而得知)被认为是网络拥塞的一个迹象,TCP将相应地减小窗口长度;
- 在网络辅助的拥塞控制方法里,网络层会向发送方提供关于网络中拥塞状态的显式反馈消息,比如使用一个比特位来指示网络是否拥塞;拥塞信息从网络反馈到发送方一般有两种方式:
- 其中直接反馈信息可以由网络路由器发送给发送方,这种方式的通知通常采用一种拥塞分组的形式;
- 第二种形式的通知是路由器标记或者更新从发送方到接收方的分组中的某个字段来指示拥塞的产生,然后由接收方向发送方通知该网络发生了拥塞。
📚TCP拥塞控制原理
参考学习博客:TCP的拥塞控制
- 我们将TCP发送方的丢包事件定义为:要么超时,要么收到接收方的3个冗余ACK;
- 一个丢失的报文段意味着拥塞,因此当丢失报文段时应当降低TCP发送方的速率;
- 一个确认报文段指示该网络正在向接收方交付发送方的报文段,因此,当收到对先前报文段的确认时,可以增加发送方的速率;
TCP的拥塞控制
🐇慢启动
- TCP连接在开始的时候,其cwnd常设置为一个MSS,然后在慢启动状态每收到一个ACK,cwnd就增加一个MSS;这样的话,在慢启动阶段,发送速率是指数增加的(1,2,4,8…)
- 何时结束这种指数增长?有三种情况:发送了超时、发生了冗余ACK以及cwnd达到ssthresh。ssthresh是慢启动阈值的速记。
- 在慢启动阶段,如果发生了超时事件,那么ssthresh就被设置为当前cwnd的一半,然后将cwnd置为1;当cwnd逐步增加到ssthresh时,再翻倍增加cwnd就有一点鲁莽了,所以此时TCP结束慢启动,进入拥塞避免模式。
- 在拥塞避免模式里,TCP将更谨慎地增加cwnd;如果收到冗余ACK,那么TCP会做一次快速重传,然后进入快速恢复阶段;
🐇拥塞避免
- 一旦进入拥塞避免状态,cwnd的值大约是上次遇到拥塞时的一半,所以TCP在每个RTT中,只将cwnd增加一个1个MSS大小;也就是说在拥塞避免阶段,cwnd是线性增加的;
- 当出现超时时,TCP将cwnd设置为1,然后将ssthresh更新为cwnd(发生拥塞时的cwnd的值)的一半;
- 当收到冗余ACK时,TCP将cwnd减半,然后将ssthresh置为cwnd值的一半,并且进入快速恢复状态;
🐇快速恢复
- 快重传即TCP将cwnd减半,然后将ssthresh置为cwnd值的一半。
- 在快速恢复阶段,对于引起TCP进入该状态的缺失报文段,每收到一个ACK,cwnd增加一个MSS(即ssthresh+3,因为是3次重复确认)。最终,当对丢失报文段的一个ACK到达时,TCP降低cwnd后进入拥塞避免状态。如果出现超时事件,快速恢复在执行如同慢启动和拥塞避免中相同动作后,进入慢启动状态。
参考教程:《计算机网络自顶向下方法》
参考博客:计算机网络自顶向下学习笔记