本文部分图片(PPT截图)来自中科大计算机网络top down
3.0 目录
[TOC]
3.1 概述
传输层TCP和UDP协议可以在IP协议主机到主机通信的基础上,实现进程到进程之间的通信(利用端口号)真正实现端到端的通信【通过多路复用于解复用】
传输层的TCP协议可以提供可靠性的服务(RDT),但是并不能改进延时和吞吐量的性能,也不能提供安全性的保障(应用层中的SSL: Secure Socket Layer)
3.2 多路复用与解复用
A. 形象理解
生活中的示例:Anne家12个小孩,Bill家10个小孩,每个月Anne家的每个孩子都要给Bill家的每个孩子写邮件,示意图如下:
120封信通过邮局发出相当于多路复用过程,Bill家大孩子分信相当于解复用的过程
B. 原理分析
多路复用的过程:创建套接字socket,与应用进程的进程号相互关联,并利用套接字的源端与目的端IP和Port创建TCP\UDP报文段和IP数据报的头部
解复用的过程:传输层获取到源IP,目标IP,源Port以及目标Port之后即可查询本地的Socket表,便可以得知创建该套接字的应用进程
3.3 UDP协议
UDP:User Datagram Protocol用户数据报协议
UDP有什么用武之地呢?【流媒体应用】(要求实时性较高)、【DNS域名系统】(典型的事务性应用)、【SNMP简单网络管理协议】
A. UDP报文头部
UDP是面向报文的协议【报文是有界的】,TCP是面向字节流的协议【字节流是无界的】
UDP报文的头部总共8个字节(2*32bits = 8Bytes)
报文长度是以字节为单位的报文长度(包含头部的8个字节)
B. UDP差错检验EDC(校验和)
EDC:Error_Detection and Correction差错检测与纠错
将整个UDP数据报切成一个个16bits的段(头部也要切),并将所有段加起来
得到校验和需要两个技巧:进位回滚+按位取反
3.4 可靠数据传输RDT
本节采用渐进的方式讲述RDT即从下层完全可靠开始,逐步加入不可靠的因素,并了解相应的RDT可靠数据传输机制的可靠性措施
且本节采用有限状态机FSM:Finite State Machine的形式来描述发送和接收方的状态,有限状态机的形式如下:
A. RDT1.0 下层可靠信道的可靠数据传输
下层提供的服务无比特差错,无分组丢失,完全可靠
本层只需要增加多路复用与解复用服务即可
因此,对于应用层交到传输层的报文,只需要进行封装并递交给网络层,对于接收方网络层上交的报文段也只需要解封装并通过解复用上传给应用层进程即可
其有限状态机如下:
B.RDT2.0 具有比特差错的下层信道
下层信道可以具有bit差错(把0传成1)因此需要有传输确认的机制(ACK+NAK),以及校验和checksum校验的机制(进位回滚+按位取反)
因此,发送方发送报文段后进入等待确认的阶段,如果受到ACK,则说明接收方成功受到并校验通过报文段,因而发送发可以进入下一个等待上层调用的周期
而接收方接收到报文段后,需要利用校验和校验报文,校验不通过,返回标志NAK,并丢弃错误报文,等待报文重新传输;校验通过,返回标志ACK,并解封装报文,通过解复用传递给应用层进程
其有限状态机如下图所示:
C. RDT2.1:解决2.0中ACK,NAK传输出错问题
RDT2.0中有个致命的不足,若ACK或NAK在传输的过程中发生错误,或无法到达,那么发送端将一直处于等待回复的状态,接收端也将一直处于等待包裹的状态,系统死锁
因此,RDT2.1中加入了序号机制以及对ACK与NAK的校验机制
首先,对ACK与NAK的校验机制目的是验证ACK与NAK在传输的过程中是否有发生错误
接着,引入编号对解决ACK以及NAK传输错误的问题有什么作用呢?不是加入校验机制就可以了吗?
对于发送方而言,确实不需要编号的机制,只要收到一个不知道是啥的反馈,再将本分组发出去即可,因此,引入编号对发送方是没影响的
但是对于接收方而言,如果不引入编号,那么我们可以假设以下两种情景:
发送方给接收方的报文校验不通过,接收方本来要返回NAK,但NAK在返回的图中挂了,那么发送方重新传递该报文是没问题的
发送方给接收方的报文校验通过了,而接收方本来要返回ACK,ACK在半路挂了。如果没有序号,那么接收方将回到等待下层报文到来的阶段,如果再次收到原报文,那么接收方也会当作正常的报文解封装传递给应用层进程,导致同样的报文重复传递。即原本应该传递pkg0和pkg1但是现在由于返回的ACK半路挂了,因而接收方向其应用进程输送了两次pkg0,显然是有问题的
因此,编号机制对于接收方不重复传递是有重要意义的
RDT2.1的有限状态机如下:
D. RDT2.2:NAK_free版本的协议
在RDT2.2版本中,用上一个分组的确认号代表本分组的拒绝,从而实现了NAK_free的协议,从而有利于后面pipeline高效可靠数据传输的实现
RDT2.2的实现示意图如下:
即若发送方发送的分组1校验失败,则接收方发送ACK0表示收到分组0,未收到分组1,因此发送方将重新发送分组1。特别地,若第一个分组未收到,则发送ACK1,代表校验失败。
E. RDT3.0:完备的停止等待(stop and wait)协议
上述的RDT2.1和RDT2.2协议虽然解决了ACK和NAK在传输过程中发生错误的问题,但由第一章中分组交换的知识知道:当中间交换节点队满时,到来的分组会直接被丢失,使得丢包的出现。
若线路出现丢包,发送方处于等待回复的状态,而接收方处于等待分组的状态,那么系统又会进入死锁的状态中,需要新的机制打破死锁。
RDT3.0中采用了超时重传的机制打破上述的死锁,发送方在发送了分组之后开始计时,当时间超过设定的时间后,则重新发送该分组。【超时时间如何计算将在TCP协议部分进行详述】
RDT3.0的有限状态机如下两图所示:
需要特别说明的是,上面⭐A的部分,A部分代表什么都不干。可能你会有问题:在前面协议RDT2.1里面,如果收到了NAK或者是收到了错误的回复,不是应该要重传该报文吗?为什么这里啥也不干呢?
其实,这里有点版本兼容性的原因,在RDT3.0中,采用了超时重传的机制,因此不论什么情况,只要达到超时时间,都需要重传分组。因此,在收到拒绝或者错误的回复时,RDT3.0协议不急着立马重传,而是等着超时时间到再重传。
为了理解更加深入,我们再就着上面的有限状态机推演一遍停止等待协议的循环:
首先应用层调用原语要发送分组0,则发送端保存分组0的副本,并向接收端发送数据+校验和+分组序号0。发送端进入等待回复0的状态。
接收端接收到分组0,校验正确,并向发送端发送ACK0的回复,将分组0解封装,解复用后发送给应用层应用进程。接收端进入等待分组1的状态。
接收端发送的ACK0在传输过程中发生错误,传送到发送端,发送端啥也不干,等着超时事件的到来。
超时时间到,发送端重新发送分组0,并重新开始计时,继续进入等待回复0的状态。
接收端再次收到分组0,校验通过,于是接收端将分组直接丢弃,并向发送端发送ACK0。
成功接收到ACK0后,发送端停止计时,并进入等待应用层调用发送分组1的请求,循环完成。
F. Pipeline流水线协议
停止等待协议是每次发送一个分组,并且等待收到正确回复之后才能发送第二个分组,这种方式在局域网还能凑活,如果到了广域网就明显效率太低了,就像华南快速干线每次只能通过一辆车,这辆车走完了才允许第二辆车走,明显不行。
我们做一个小计算:现有发送方Sender与接收方Receiver建立了联系,两者建立联系的往返延时RTT = 30ms,现有报文的大小为L = 1000kB = 8000kbits,网络带宽为R = 1Gbps。则发送时延为t = L/R = 8μs,因此,网络的利用率为:
因此,对于较大型的网络,流水线协议非常有必要
F1. 滑动窗口协议(Sliding Window)
发送缓冲区与发送窗口
首先,在前面讲到分组交换的时候我们曾提到过发送缓冲区,用来保存要发送的分组,如果发送缓冲区满,那么后来的数据分组将被直接抛弃,造成丢包。
而发送窗口是发送缓冲区的子集,是可以发送的数据。例如发送缓冲区可以存储10个数据分组,而发送缓冲区的最大尺寸为4。因此对于报文0,1,2,3而言,可以直接发送,而报文4则需要等待
发送窗口类似于一个队列,有头尾两个指针,初始状态头尾指针同时指向发送缓冲区的头部,当应用层发送来一个报文,头指针前移,尾指针不变【在发送窗口不超过最大值的情况下,循环上述操作】
在发送窗口内的报文可以发送,发送却未收到回复的报文依旧保留在发送窗口中,并用超时重传定时器控制是否需要重发(不同协议的定时器设置不同),如果发送窗口的分组得到正确的确认,那么发送窗口尾指针后移。
旧的分组完成正确确认,新的分组可以进入发送窗口中,实现发送窗口的滑动。且由于发送缓冲区的大小是有限的,因而双指针在滑动的过程中需要进行取模的操作【类似循环队列的操作】
接收窗口
接收窗口限定了网络可以同时接收的分组的数目,如果接收窗口的大小为1,那么发送方发送的数据必须顺序到达,而如果接受窗口大于1,那么允许发送方发送的数据乱序到达
Sliding Window与Stop and wait``Go Back N以及Selective Repeat
发送窗口的大小为:SW,接收窗口的大小为RW
SW = 1 && RW = 1:停止等待协议Stop and wait
SW > 1 && RW = 1:回退N步协议Go Back N
SW = 1 && RW = 1:选择性重传Selective Repeat
F2. 回退N步协议(Go Back N)
发送窗口大小大于1,接收窗口值等于1
发送端发送窗口内的所有报文(P0,P1,P2),并打开超时重传定时器【GBN协议只维持一个超时重传定时器】。接收端的接收窗口等待接收P0
如果发送端P0最早到达,那么接收端将返回ACK0,代表P0接收成功,并将接收窗口移动到P1
如果发送端成功接收到ACK0,那么发送端将定时器重新开始计时,并将发送窗口后移一位,可以发送新的分组
但是,分组1在传输过程中丢包了,因而发送端发送的分组P2比P1先到达接收端,接收端接收到P2分组,返回ACK0,代表没有接收到期望的分组P1,发送窗口不动,继续等包裹
此时,发送端接又一次收到了ACK0,重启计时,并且等着超时。到了超时时间,发送端就把从P1开始的所有分组又重新发出去,重新计时,等待ACK1的到来
GBN协议的有限状态机如下图所示:
F3. 选择性重传协议(Selective Repeat)
发送窗口和接收窗口都大于1
允许出现传输的乱序,并可以利用接收窗口的容量实现乱序分组的纠正
选择性重传协议的示意图如下:
我们跟着上图推演一下过程,深入理解协议的过程:
首先发送方向接收方发送分组P0,P1,P2,P3,其中,P0,P2,P3都正常传递,而P1在传递的过程中发生的丢包
因此,接收端最先接收到分组P0,则直接将P0解封装上交给应用进程,并将接收窗口后移一位
由于分组P1丢包,因此接收端无法收到该分组,但可以正常接收分组P2和P3。但是在接收了分组P2和P3之后,接收端并不解封装上交,而是等着P1分组的到来。并且向发送端发送确认报文ACK2和ACK3,那么确认报文ACK2和ACK3会让发送端的P2,P3对应的超时重传定时器停止计时。
分组1丢包必然导致P1对应的超时重传定时器到时,因而发送方会重传P1分组。该分组成功传达后,接收端会对P1,P2,P3进行解封装,并将三个分组称递给应用进程,实现顺序的纠正
G. GBN与SR协议的对比
GBN协议维持一个超时重传定时器,但是遇到超时的情况需要将发送区内的所有内容都发送出去
SR协议维持多个超时重传定时器,遇到超时的情况可以有针对性地发送不能正常传递的分组
GBN协议较简单,但出错的代价比较大,因此适合于出错几率比较低的网络
SR的协议较复杂一些,但是出错的代价小,因而适合于比较容易出现传输乱序的网络
3.5 TCP协议
由于需要建立连接,仅能提供一对一的服务,而UDP可以提供一对多,多对多的服务
TCP是面向字节流的协议,而UDP是面向报文的协议,TCP不维护报文的界限,而是将报文切成一个个MSS:Max Segment Size大小的报文段
TCP是流水线形式的;且为了匹配发送和接收的速率,设置发送和接收缓存;且全双工通信,即发送和接收是同时同步进行的
TCP具有流量控制和拥塞控制
A. MSS最大报文段大小
对于任何物理网络,都具有MTU:Max Transfer Unit最大传输端元。对于以太网而言,最大的数据传输单元的大小是1500Bytes
而每一个报文段需要加上TCP头部以及IP头部需要恰好可以封装成帧的载荷部分
而TCP头部和IP头部都是20Bytes因此MSS为1460
B. TCP报文结构
序号(以字节为单位):序号和前面RDT中的PDU序号是不一样的,TCP报文中的序号是每个MSS的第一个字节相对整个字节流首位的偏移量
两个应用进程在建立TCP连接时初始的字节号不是为0的,因为需要防止滞留在网络中的分组对其造成影响
确认号ACK(以字节为单位):确认号的含义:如对方发回来的ACK=555,代表我已经收到了554以及以前的所有字节,期待你从555字节开始发送。这个定义和我们讲RDT时候的定义是不太一样的
用一个例子在加深序号Seq与确认号ACK:
C. TCP超时定时器时间的设置
超时时间太短,会使得分组出现没有必要的重发;超时时间太长,会使得网络过于消极,等待时间太长
且对于多跳的网络,其超时时间波动较大,即概率密度函数较为矮胖,难以挑一个固定的时间,但是对于每一个短的时间而言,其分布比较集中,概率密度函数比较高瘦,可以选出一个合适的值,因此要采用一个适应式的时间设定策略
上一时刻的平均往返时延为EstimateRTT0,本时刻测定其中一个分组的往返延时SampleRTT,因而本时刻平均往返时延为(移动平均值):
上一时刻的偏差为DevRTT0,本时刻的偏差为|SampleRTT-EstimateRTT1|,因此同样由滑动平均的策略可以得出本时刻的往返时延偏差(可以认为是方差):
因此我们设定的超时时间间隔为(类似概率中的3σ原则):
D. TCP的可靠数据传输
TCP的RDT是GBN与SR协议的混合体
TCP采用累计确认的方式,而不是逐段确认
TCP仅设置一个定时器,这一点和GBN协议是一样的
但是TCP定时器是随着最老的段发出开始计时的,而当定时器到时,TCP协议会仅将最老的段发出,而不是把窗口内所有报文发出,这一点和SR协议很像
如果TCP收到了乱序报文段,报文段怎么处理是可以自定义的。像GBN一样抛弃,或者像SR一样存下来都可以
D1. TCP的重传机制
如果超时定时器到时,肯定要重传
如果在收到一个正确的报文段确认后,又收到三个冗余的报文段确认,而超时时间依然没到,那么会进行快速重传。
也就是发送端发送了P0,P1,P2,P3,P4,P0报文段正常送达,但是P1丢包了,P2,P3,P4都陆续送到,因此又传回了三个冗余的确认,因此,TCP启动快速重传机制,传出发送窗口中最老的一个报文P1
D2. TCP的有限状态机(不包括流量和拥塞控制)
在收到ACK的部分,实际的TCP协议会加入快速重传算法,快速重传前文已经讲解,不再赘述
E. TCP的流量控制
发送方发送的文件速度太快,而接收方处理不过来
TCP报文的头部有一个Receive Window的字段,通过报文返回,发送方即可得知现在接收方接收窗口的大小,并可以以此来控制发送方发送窗口的大小。发送窗口的计算公式如下:
其中,SendWindow是发送窗口的大小,ReceiveWindow是接收窗口的大小,CongestionWindow是拥塞窗口的大小
接收窗口的计算公式如下:
其中,RcvBuffer是原始整个接收窗口的大小,LastByteRcv-LastByteRead是已经占用的接收窗口大小,LastByteRcv是最近收到的最后一个字节,LastByteRead是最近完成读取的最后一个字节
捎带技术Piggybacking:捎带技术就是把数据和确认信息合并在一起(相当于农夫1给农夫2送了一头🐖,农夫2会送给农夫1送回一头🐏,并且在🐏屁股上贴一张纸条,说我已经收到你的🐖了【确认ACK】,我的农场还要5头🐖的位置【接收窗口大小】)
F. 连接管理:连接建立+连接拆除
F1. 两次握手可以吗?
两次握手即连接请求+连接建立有什么问题呢?
两次握手失败的场景如下图所示:
上图左边的情况,如果仅有两次握手,那么服务器端必定在接收到请求报文之后就会进入连接状态,同时发回连接确认报文。这就造成了服务器先进入连接状态,而用户后进入连接状态,那么如果连接确认报文传输有误,或者连接请求报文超时重传,而在重传的过程中连接被用户断掉了,就有可能出现只有服务器在傻傻地处于连接状态【半连接】,而用户其实并没有维持连接状态
右边的失败情景也是由于服务器先进入连接状态,而把旧的数据当成新的数据接收了
F2. 三次握手
TCP三次握手的示意图:
TCP解决两次挥手的失败情景:
对于可能存在的半连接情况:服务器端接收到迟到的连接请求,并发回连接确认,此时这个连接确认会直接被客户端拒绝
对于可能存在旧数据被当成新数据接收的情况,由于连接根本没有建立起来,所以当然不会接收该数据
诡异的可能失败情景以及解决办法:
对于上述右边情况,可能会存在一种更诡异的情形:假定客户端的端口为555,服务器的端口为80,第一次连接建立,有一个报文(图中的data(x+1))一直在网络里面飘。等到第二次客户端又以555端口与服务器的80端口建立连接,那个报文才到,这就有旧报文被当成新的报文接收的风险。
解决:我们不选择固定的值作为序号,而是随机选择一个32位比特作为序号的开始【可能利用时间作为随机数产生器】,这样可以最大程度避免老数据对新连接的影响
F3. 连接结束(四次挥手)
分两个方向进行连接拆除
首先,客户端向服务器发起连接拆除,服务器回复确认,那么就没有数据从用户传递给服务器了,但服务器还可能有数据传回来客户端
接着,服务器也传完了数据,那么就再次向客户端发来连接拆除请求,得到客户端的确认,之后没有数据从服务器传给客户端,整个连接完全拆除
依然不完美,存在两军问题,都有可能存在一方维持连接的问题
3.6 拥塞控制
A. 拥塞控制与流量控制的区别
流量控制是我和你的问题,即发送方与接收方的问题
而拥塞控制是针对公共网络的控制
就像某博物馆一天只能容纳100人,而一个学校一个年级10000人,那么流量控制就是学校每天只能有100人去博物馆,而拥塞控制则是这100个人在去往博物馆的图中尽量不要遇到塞车等情况
B. 网络拥塞的原理
网络拥塞的表现1:延时特别大(当流量强度->1时,排队延时->+∞)
由第一章的排队延时与流量强度的关系可以知道,当网络阻塞程度增加,流量强度I->1因此延时t_queue->+∞
网络拥塞的表现2:降低了goodput,为了达到有效的输出,我得输入更多的数据(因为超时重传的比例越来越大)。而且造成重复,由于网络延时急剧增加,因此非常多的分组原本并没有丢,但是都进行了重发,导致严重的重复,进而拥塞的情况越来越严重,相当于一个正反馈
网络拥塞的表现3:网络死锁+浪费上游传输能力
在上图可以发现,当红色流量处于上游的时候(就是红色流量刚刚发出,流量最大,竞争力最强的时候),与之竞争的是蓝色的下游流量【上面的路由器】,因此红色流量竞争力大,导致蓝色流量大量丢包
同样到了红色流量的下游路由器【右边的路由器】,红色流量减小,竞争力减小,而恰好遇到绿色的上游流量,因此红色流量丢包率大大上升。
其他的流量也是如此,整个网络进入死锁,上游流量传输到下游被大量丢包
C. 拥塞控制方法
C1. 端到端的拥塞控制方法(TCP)
端系统自身判断网络是否发生拥塞
TCP依靠如分组丢包,冗余确认等指标进行判断
C2. 网络辅助信息的拥塞控制
网络核心会提供拥塞信息给端系统
端系统根据信息控制发送
D.ATM异步传输网络的拥塞控制方法(网络辅助信息拥塞控制)
ATM网络的数据单位是信元(短小53Byte)
线路交换的每个节点消耗1Byte的时间,而分组交换在每个节点消耗1分组的时间(1个分组通常1000+字节),因而ATM网路介于两者之间
ABR:Available Bit Rate,例如ATM网路的正常带宽是1Mbps,那么在不发生拥塞的时候可以尽可能发送,而发生拥塞的时候,必须控制发送的速度不能超过1Mbps
信元分成两类,数据信元以及资源管理RM信元,RM信元中有NI bit:No Increase in rate轻微拥塞信元以及CI bit:Congestion Indication拥塞指示信元,ATM交换设备发现网路出现拥塞的情况,那么会将报文的对应位置位,因此就可以让端主机知道网络的拥塞情况
且资源管理信元中还有ER:Explicit Rate字段,代表网络可以为该对连接提供多少带宽,信元每次经过交换设备,交换设备会将可以提供的带宽与现有的ER字段的值进行对比,如果比现有的值小,那么就存入作为新的ER值
3.7 TCP拥塞控制(端到端拥塞控制)
网络辅助信息拥塞控制的不足:网络交换设备的负担较大,对于大型网络,成本开销很大
而TCP协议的端到端拥塞控制,将最复杂的部分放在网络边缘,而网络核心部分采用最简单的设计
A. 如何检测拥塞?
超时时间的发生【拥塞】:超时说明网络发生拥塞,延时增大,此时应该降低发送速度;也可能是分组在传输过程中受到干扰,导致出错,无法通过校验和的校验,此时不应该降低发送网络,但是这种情况发生的概率是非常低的,所以问题不大
冗余确认【轻微拥塞】:某一个分段丢了,但后面的几个段都顺利到达了,说明拥塞传不到的情况还不是很普遍,因此是轻微拥塞【冗余确认与快速重传算法见前面TCP网络部分】
B. 如何控制发送速率?
在发送端维持了一个变量,rate是拥塞控制的速度,CongWin是在对方未确认的情况下可以向网络注入多少字节
超时或者3个重复ACK,CongWin↓
超时:CongWin降为1MSS,在SS慢启动阶段,然后倍增到CongWin/2(每个RTT),然后进入CA阶段
3个重复ACK:CongWin降低为CongWin/2,进入CA拥塞避免阶段
正常收到ACK的时候,CongWin↑
SS:Slow Start慢启动阶段:每个RTT,拥塞窗口值CongWin加倍
CA:Congestion Avoidence拥塞避免阶段:每个RTT,拥塞窗口值CongWin线性增加
C. TCP拥塞控制与流量控制联合控制动作
发送窗口的大小由空闲缓冲区(接收窗口值)以及拥塞窗口值的大小限定 ,可以同时满足拥塞控制和流量控制的要求
D. 拥塞控制策略
慢启动
TCP建立的时候,CongWin设定为1MSS
每受到一个确认,拥塞窗口值CongWin+1,也就是每一轮(每个RTT)CongWin翻倍
翻倍的CongWin很快就会导致超时,假设超时的阈值为CongWin_0,那么超时之后,将CongWin = 1并且将CongWin_0/2作为警戒值,在[CongWin_0/2,CongWin_0]区间内进行拥塞避免阶段,在拥塞避免阶段即不能再翻倍了
线性增加,乘性减小
由拥塞控制决定的平均吞吐量(忽略慢启动阶段的时间),拥塞窗口值为W:
E. TCP的公平性
情况一:AA'和BB'是两对主机,都建立了一对TCP连接,而且两者的往返时延是相同的,其中有一段主干链路都是两者的带宽瓶颈链路,且其带宽为Rbps,那么两者是公平享有一半的带宽的
根据上面的图可以发现,每当AA'和BB'发生超时事件,AA'和BB'都会减半,朝着AA'和BB'相等的方向发展,最终达成公平
情况二:AA'采用TCP协议进行通信,BB'采用UDP连接
此情况是不公平的,因为TCP协议是有流量控制和拥塞控制的,但是UDP是没有的,因而UDP对带宽具有极强的侵略性,占据很大的带宽
情况三:AA'中建立了9对TCP连接,而BB'只建立了1对TCP连接,两者的往返时延相同
那AA'将占用0.9的带宽,BB'只占用0.1的带宽
情况四:AA'与BB'都只建立了一对TCP连接,但是AA'的往返时延短一些
根据上面吞吐量的公式,显然有AA'占据的带宽要大一些