传输层位于应用层和网络层之间,是分层的网络体系结构中重要的部分,该层为运行在不同主机上的应用进程提供直接的通信服务起着至关重要的作用。在这里我们将讨论两个大的问题:将网络层在不同端系统之间的通信服务扩充到运行在两个端系统上不同的应用层进程之间的通信服务(如何实现进城之间通信的可靠传输)和控制传输层实体的传输速度以避免网络拥塞或者从网络拥塞中恢复过来,这里需要考虑的有拥塞的后果和原因以及常见的拥塞控制手段,特别的,我们将了解TCP协议中的拥塞控制。
在发送方主机多路复用:从多个套接字接受来自多个进程的报文,根据套接字对应的IP地址和端口号等信息对报文段用头部加以封装(该头部信息用于以后的解复用)
在接收方主机解复用:根据报文段的头部信息中的IP地址和端口号将接收的报文段发给正确的套接字(和对应的应用进程)
TCP提供了可靠数据传输,并且提供了拥塞控制,为什么人们还需UDP呢?事实上,有些应用很适合UDP(因为没有连接过程啊,因为不会受拥塞控制的调节啊,更自由);UDP有以下好处:
可靠数据传输为上层实体提供的服务抽象是:数据可以通过一套可靠的信道进行传输,借助于可靠信道,传输数据就不会受到损坏或者丢失;并且所有数据都可以按照其发送顺序进行交付。而这正是TCP向调用它的应用所提供的服务模型
单方向的可靠数据传输流程大概是这样的:可靠数据传输->不可靠数据传输->不可靠的传输信道->可靠数据接收->上传Data
一个可靠数据传输协议,将要面对以下问题:分组丢失、分组损坏到达、分组乱序到达。总结可靠传输需要的技术:检验和、序号、定时器、肯定和否定确认分组。
假设所有发送的分组都可以按其发送顺序被接收。基于重传机制的可靠数据传输协议称为自动重传请求协议(ARQ)。增加了ACK和NCK
ARQ协议中还需要另外三种协议功能来处理存在比特差错的情况:差错检测,接收方反馈,重传。
rdt 2.0的发送端每发送一个分组需要等待接收端的确认信号,这种协议被称为停等协议。
rdt 2.0 中有一个致命的缺陷,就是没有考虑到 ACK 和 NAK 分组受损的可能性。
考虑ACK和NAK受损的个两可能性:
解决这个新问题的一个简单的方法就是在数据分组中添加一个字段,让发送方对其数据分组编号,即将发送数据分组的 序号 放在该字段。于是,接收方只需要检查序号即可确定收到的分组是否一次重传。
如果不发送NAK,而是对上次正确接收的分组发送一个ACK,我们也能实现同样的效果。
发送方接收到对一个分组的两个ACK(冗余ACK)后,就知道接收方没有正确接收到跟在确认两次的分组后面的分组。
rdt 2.2 是在有比特差错信道上实现的一个无NAK的可靠数据传输协议。
rdt 2.1和rdt 2.2的区别在于,接收方此时必须包括由一个ACK报文所确认的分组序号
在 rdt 3.0 中,丢包的问题让发送方解决。不管是发送的分组丢失,还是接收方返回的确认分组丢失,只要在经过一定的时延后,让发送方重发该分组即可。
由此产生的 冗余数据分组 则由接收方通过序号处理。为了实现基于时间的重传机制,需要一个倒计时定时器
因为分组序号在 0 和 1 之间交替,因此 rdt 3.0 有时被称为 比特交替协议。
rdt 3.0 是一个功能正确的协议,但是由于它是一个停等协议,大部分的时间都浪费在等待确认上面,所以性能不好。
解决这种特殊性能问题的一个简单的方法是:不使用停等方式运行,允许发送方发送多个分组而无需等待确认。这种技术被称为 流水线。
要使用流水线技术,则须:
流水线的差错恢复有两种基本方法:
在回退N步中,发送方维护一个N——窗口大小和一个base——发送方期待收到的最小待确认分组序号,同样也是窗口的起点,还有一个next Sequence变量,表示上层需要发送分组时,可以使用的序号。这样全部序号就被划分为0-base-1,这一部分的分组是已发送且收到接收方确认的分组,base~next Sequence-1这一部分的分组是已发送但是尚未收到确认的,其中base是尚未收到确认的最小序号;next-1~base+N-1表示当前发送方可以使用的序号,表示一种发送能力;当发送方收到确认号为base的确认分组后就会向前移动窗口,所以回退N步也被称为滑动窗口协议
这是发送方需要维护的数据,同时发送方需要响应的事件有:上层调用、收到ACK、超时事件;
在GBN中发送方看到的序号
N为窗口长度,GBN协议也经常被称为滑动窗口协议
运行中的GBN:
窗口长度为4个分组的GBN协议的运行情况。因为该窗口长度的限制,发送方发送分组0-3,然后在继续发送之前,必须等待直到一个或多个分组被确认。当接收到每一个连续的ACK(例如ACKO和ACK1)时,该窗口便向前滑动发送方便可以发送新的分组(分别是分组4 和分组5)。在接收方,分组2丢失,因此分组34和5被发现是失序分组并被丢弃。
选择重传(SR)协议通过让发送方仅重传那些它怀疑在接收方出错(即丢失或受损)的分组而避免了不必要的重传。这种个别的、按需的重传要求接收方逐个地确认正确接收的分组。再次用窗口长度N来限制流水线中未完成、未被确认的分组数。然而,与GBN不同的是,发送方已经收到了对窗口中某些分组的ACK。图3-23 显示了SR发送方看到的序号空间。
选择重传(SR)发送方和接收方的序号空间
SR操作
SR 接收方将确认一个正确接收的分组而不管其是否按序。失序的分组将被缓存直到所有丢失分组(即序号更小的分组) 皆被收到为止,这时才可以将一批分组按序交付给上层。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6GQekFJ0-1670656224379)(https://edu-1328.oss-cn-hangzhou.aliyuncs.com/img/%E5%BE%AE%E4%BF%A1%E5%9B%BE%E7%89%87_20221209211210.jpg)]
TCP报文段结构,从整体上来说由首部+数据字段组成;其中数据字段来自应用层,其长度不能大于MSS;首部的常规长度为20字节,但是值得注意的是,TCP首部是可变长的;TCP首部是以32比特为单位组织的,如下图:
TCP的序号和确认号
设置往返延时
加权平均往返时间RTTs:新的RTTs = (1 - a) * 旧的RTTs + a * 新的RTT样本
设置超时
加权平均往返时间RTTD:新的RTTD = (1 - b) * 旧的RTTD + b * 新的RTT样本
TCP运输连接的建立和释放时每一次面向连接必不可少的过程,分为三个阶段:连接建立、数据传送、连接释放
TCP连接建立需要解决:
第一次握手
客户端向服务端发送连接请求报文段。该报文段的头部中SYN=1,ACK=0,seq=x。请求发送后,客户端便进入SYN-SENT状态。
PS1 :SYN=1,ACK=0表示该报文段为连接请求报文。
PS2 :x为本次TCP通信的字节流的初始序号。
TCP规定:SYN=1的报文段不能有数据部分,但要消耗掉一个序号。
第二次握手
服务端收到连接请求报文段后,如果同意连接,则会发送一个应答:SYN=1,ACK=1,seq=y,ack=x+1。
该应答发送完成后便进入SYN-RCVD状态。
PS1 :SYN=1,ACK=1表示该报文段为连接同意的应答报文。
PS2 :seq=y表示服务端作为发送者时,发送字节流的初始序号。
PS3 :ack = x+1表示服务端希望下一个数据报发送序号从x+1开始的字节。
第三次握手
当客户端收到连接同意的应答后,还要向服务端发送一个确认报文段,表示:服务端发来的连接同意应答已经成功收到。
该报文段的头部为:ACK=1,seq=x+1,ack=y+1。
客户端发完这个报文段后便进入ESTABLISHED状态,服务端收到这个应答后也进入ESTABLISHED状态,此时连接的建立完成!
TCP连接建立的三次握手过程
第一次挥手
若A认为数据发送完成,则它需要向B发送连接释放请求。该请求只有报文头,头中携带的主要参数为:
FIN=1,seq=u。此时,A将进入FIN-WAIT-1状态。
第二次挥手
B收到连接释放请求后,会通知相应的应用程序,告诉它A向B这个方向的连接已经释放。此时B进入CLOSE-WAIT状态,并向A发送连接释放的应答,其报文头包含:
ACK=1,seq=v,ack=u+1。
第二次挥手完成后,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发送确认应答,此时A进入TIME-WAIT状态。该状态会持续2MSL时间,若该时间段内没有B的重发请求的话,就进入CLOSED状态,撤销TCB。当B收到确认应答后,也便进入CLOSED状态,撤销TCB。
为什么A要先进入TIME-WAIT状态,等待时间后才进入CLOSED状态?
为了保证B能收到A的确认应答。
若A发完确认应答后直接进入CLOSED状态,那么如果该应答丢失,B等待超时后就会重新发送连接释放请求,但此时A已经关闭了,不会作出任何响应,因此B永远无法正常关闭。
计算机网络拥塞的原因是因为网络中的分组太多,而链路带宽和路由器缓存容量都是有限的;
TCP必须使用端到端的拥塞控制而不是网络辅助的拥塞控制,因为IP并不会向端系统提供显式的网络拥塞反馈;TCP所采用的方法是让每一个发送方根据其所感知的网络拥塞程度来限制其能向连接发送流量的速率;如果TCP判断网络通畅,那么它会提高发送速率,如果TCP判断网络拥塞,那么它会限制发送速率;需要解决三个问题:TCP如何限制发送速率?TCP如何感知网络拥塞程度?TCP该以何种算法改变其发送速率?
我们知道,TCP连接的双方都维护着两个窗口,其中一个是作为发送方的窗口,也被称为拥塞窗口cwnd,它对发送方能向网络中发送流量的速率进行了限制, l a s t s e n t − l a s t a c k e d < = m i n c w n d , r w n d last sent-last acked<=min{cwnd,rwnd} lastsent−lastacked<=mincwnd,rwnd;另一个自然是作为接收方的接收窗口。
我们假设,发送方可以在RTT时间范围内连续发送cwnd个字节的数据,所以发送速率即为cwnd/RTT;发送方通过调整窗口大小来对发送数据的速率加以控制
我们将TCP发送方的丢包事件定义为:要么超时,要么收到接收方的3个冗余ACK;如果网路拥塞,那么网络中的路由器就会发生缓存溢出,进而导致数据报被丢弃,然后就会引起发送方的丢包事件;此时,TCP发送方就可以认为TCP连接出现了拥塞
另外,TCP将接收方发送的ACK视为网络通畅的标志,如果ACK到达的速率较高,那么TCP的拥塞窗口就会以较高的速率扩大,如果ACK到达的速率较慢,那么TCP拥塞窗口的增加速度也会较慢;因为TCP使用ACK对拥塞窗口做出调节,所以也别称为自计时的;
TCP发送速率过高,网络就很容易拥塞;TCP发送方如果过于谨慎,那么就无法充分利用网络的带宽;所以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的一半;当收到冗余ACK时,TCP将cwnd减半,然后将ssthresh置为cwnd值的一半,并且进入快速恢复状态;
快速恢复