一、运输层协议
运输层协议为运行在不同主机上的应用进程间提供了逻辑通信。具体来看,就是运输层为它上层的应用层的不同进程提供了通信服务;而将它下层的网络层的端对端通信细化为进程与进程间通信。
根据封装-分层的思想,运输层为它上层的应用层屏蔽了网络核心的细节,只保留实体间的运输信道。
我们已经知道,运输层就是将主机间的信息交付扩展到进程和进程间的信息交付,而这一过程,也被称为运输层的多路复用和多路分解。
当运输层采用面向连接的 TCP协议时,这种逻辑信道仍相当于一条全双工的可靠信道。
当运输层采用无连接的 UDP协议时,这种逻辑信道仍是一条不可靠信道。
二、多路复用与多路分解
在接收端将运输层报文段中的数据交付到正确的套接字的过程称为多路分解。
在源主机从不同套接字收集数据生成报文段,然后再将报文传递到网络层的过程称为多路复用。
而关于套接字(socket),则是网络层和端系统的应用进程间传递数据的门户。
那么问题来了,既然各报文段可通过不同的套接字到达不同的应用进程,那么各个报文段和套接字是如何一一关联的呢?实际上,每个报文段头部都有一段专门用于识别所要交付的套接字的字段。这些字段则是指向不同套接字的源端口号字段和目的端口号字段,以此来与应用层的各进程相关联,故报文段到达主机后,运输层将检查其端口号,并将其定位到各自的套接字。
由上节已知,UDP协议采用的是无连接的运输层协议,故采用UDP协议的套接字与采用TCP协议的套接字会有一定的不同。
2.1无连接的多路复用与多路分解
因为UDP协议采用的是无连接的运输层协议,故UDP的多路复用分解是无连接的
一个UDP套接字是由一个二元组来标识的,该二元组包括一个目的IP地址和一个目的端口号。
2.2面向连接的多路复用与多路分解
与UDP协议相对,因为TCP协议采用的是有连接的运输层协议,故TCP的多路复用分解是面向连接的
一个TCP套接字是由一个四元组来标定的,包括目的IP地址、目的端口号以及源IP地址和源端口号。
三、TCP连接
TCP连接提供的是全双工服务:若一台主机进程A与另一台主机的进程B存在TCP连接,那么应用层数据在从进程B流向进程A的同时,也从进程A流向进程B
TCP可从缓存中取出并放入报文段中的数据数量受限于最大报文段长度(Maximum Segment Size,MSS),而MSS则由本地主机发送的最大链路层帧(即最大传输单元,MTU)决定。这里有一点需注意,MSS指的是报文段中应用层数据的长度,而不包括TCP报文段的首部。
3.1可靠连接传输协议
3.1.1停-等协议
现在假设,当一个TCP报文段出现差错,接收方通过差错检测将舍弃该报文段,然而,发送方并不知道该报文段出现差错,将继续传输其余的报文,这就会使接收的报文段产生顺序差错。
所以,TCP引入了停-等协议,即接收方在检测收到的报文段后将向发送方发送一个ACK(肯定确认)或NAK(否定确认)的分组;相应的,发送方在发出一个报文段后将暂停发送,直到收到一个ACK分组才继续传输剩余的报文段。
3.1.2应答机制
上述协议一定程度上确实解决了报文段的受损,但是,当ACK或NAK丢失或是遇到较大的时延,该连接要么将陷入等待中,要么接收方无法分辨一个ACK是重传的前一个分组还是新的分组。
所以,在需要发送的报文段中加入了1比特的新字段,它可以让接收方知道是在重传前一个发送分组还是发送一个新的分组。举个例子,假如接收方收到一个pkt0的报文段(数字0即为刚刚加入的一比特的新字段),它此时将向发送一个ACK0分组,当发送方接收到该ACK0后,它将发送下一个被置为pkt1的报文段;而此时从接收方的视角来看,它并不知道自己的ACK0报文是否发送成功,所以只能靠自己收到的下一条分组来确认:当接收方收到pkt1分组,则表明发送方已成功收到自己的上条ACK0分组;若接收方收到一个pkt0分组,则表明该分组是发送方重新发送的上条pkt0,即自己的ACK0响应分组丢失。
ACK未丢失:
ACK1发生丢失:
上图中虚线即为ACK1发生丢失,而此时发送方并未收到ACK报文,故重新发送上条分组pkt1
3.1.3定时器
还是之前的问题,当ACK或NAK丢失,发送方需等待多久才能确定分组已经丢失呢?很明显需要根据双方的往返时延来确定一个定时器,在给定的时间量过期后,发送方便可判断上个应答报文已丢失,需重传上个分组。
所以,当加入基于时间的重传机制后,发送方能够做到:①每发送一个分组(包括重传分组)便启动一个定时器;②相应定时器的中断;③终止定时器。
3.1.4滑动窗口协议
由上述的停-等协议以及定时器功能可看出,传输报文确实有了一定的保障,但是,它的传输性能却并不高
我们可以做一个假设:假如在两个端系统中传输的RTT(往返时延)为30ms,信道发送速率为1Gbps,一个分组长1000字节(8000bit),则此时所需时间为8000/10^9,即为8μs,但30ms相对于8μs却非常长,而此时信道的利用率为8μs/(8μs+30ms)=0.027%
由此可见,信道的利用率是非常低的。
而为了解决这一问题,我们可以每次连续传输多个分组,以此提高信道的利用率。
当然,每次发送多个分组也会产生一系列问题:①需为每次传输的多个分组一个序号来保证接受顺序(可参考前文所述的ACK0/ACK1分组);②因为存在传输时延,接受双方须确定返回的确认的报文是此次TCP传输的分组还是上一次TCP传输中的某个分组
为了解决上述问题,我们可以在接收方和发送方设置一个窗口来统一管理一次传输中的若干个分组,这就是我们这节要介绍的窗口协议。
这里介绍一下,假如窗口的长度设置为1,这就退化成我们之前介绍过的停-等协议,所以有关窗口的长度以及分组的序号都可参照停-等协议来理解。
回退N步
在发送方,假设发送5个序号为0、1、2、3、4的分组,如果接收方返回一个ACK0,即分组0已被确认,则发送方窗口向前移动一位,然后依次类推。
这里介绍一下累积确认机制,当ACK报文由于一些原因丢失,那么发送方收不到对应序号的ACK报文,是不是就要重新发送呢?答案是不一定,还是以上个例子,假如ACK2、ACK3丢失,但是发送方却正确接收了ACK4,则表明,在发送方来看,接收方以正确收到序号4及其序号以前的分组。
然后我们从接收方来解释累计确认机制,假设现在发送方的分组2丢失,分组3和分组4到达,接收方是不会发送ACK3和ACK4的,而是忽视分组3和4,直至它收到一个分组2。即它将退回到收到分组2的那个时刻,这就是回退n步。
上图即可较为形象地解释回退n步协议。
选择重传
顾名思义,选择重传(SR)协议通过让发送方仅重传那些它怀疑在接收方出错的分组二避免了不必要的重传。
还是以上情况,当发送方传输的分组2丢失,分组3和分组4到达,接收方此时不但不会抛弃这两个正确到达的分组,而且还会将其缓存起来,并且继续向发送方发送ACK2,这样在一定程度上就避免了一些已正确交付的分组重复传输。
对选择重传而言,对每个分组是需要单独确认的,所以要为每个分组单独设置一个计时器
3.2流量控制
我们在应用层已经提过,多数分组交换机都会采取存储-转发机制(即一个交换机在完整收到一个分组前,都不会向下个分组机发送已收到的部分分组),那么无论是主机还是交换机,都应有自己的接收缓存来临时存储这些正在接收的分组。然而,当接收方处理数据的速度低于其接收数据的速度,那么将可能出现接收缓存溢出,分组丢失的情况,那么这时候就需要我们的流量控制协议了。
流量控制协议将通过控制发送窗口和接收窗口的长度来避免流量过多导致的分组丢失情况,在这里,我们首先做出以下几个定义:
- LastByteRead:接收方应用进程从缓存读出的字节流的最后一个字节的编号
- LastByteRcvd:放入接收方缓存的字节流的最后一个字节的编号
- LastByteSend:发送方发送的字节流的最后一个字节的编号
- LastByteAcked:发送发收到的应答字节流的最后一个字节的编号
- rwdn:接收窗口长度
- RcvBuffer:接收缓存大小
必须满足:
①LastByteRcvd-LastByteRead≤RcvBuffer
②LastByteSend-LastByteAcked≤rwnd
而接收窗口大小
rwdn=RcvBuffer-(LastByteRcvd-LastByteRead)
流量控制协议还规定,当接收方接收窗口为0时,发送方会继续停止发送剩余分组,转而发送一个只有1字节的报文段;此时接收方因为不再收到报文,则将慢慢处理接收窗口中的数据,当处理完最后的那1字节的报文段时,会向发送方发送一个表明自身窗口已清空的报文,那么这时发送方将才继续发送剩余分组。
3.3拥塞控制协议
如果说,流量控制协议是避免单个端系统出现分组丢失的话,那么拥塞控制协议就是防止整个网络因流量过大而产生的拥塞问题。所以,我们可以把拥塞控制协议看作是一个应用于整个网络层面的流量控制协议。
拥塞控制协议主要是通过限制网络中发送方传输报文的速率来控制整个网络的拥塞程度的,所以,对发送方的控制主要体现的以下几个方面:
①拥塞窗口
对于发送方窗口长度,有:
LastByteSend-LastByteAcked≤min{cwnd,rwnd}
(其中,cwnd称为拥塞窗口,它是随网络状态动态变化的)
所以说,现在发送方中未被确认的分组数量不但受到接收窗口的限制,还受拥塞窗口的限制。
②慢启动
当一个TCP连接开始时,发送方为了找到一个适合的传输速率,把cwnd设置为以1个报文段的速率进行传输,每经历一个RTT且正确收到确认报文后,它的速度将翻一番(1变2,2变4,4变8…);如果这时候出现一个丢包事件,发送方就将cwnd设置为1并重新开始慢启动过程,与此同时,它将一个一个叫做“慢启动阈值”的量设置为cwnd/2,当下一次cwdn的值达到“慢启动阈值”时,它将进入拥塞避免状态。
③拥塞避免
每经历一次RTT且未发生丢包,这时cwnd不再翻倍增加,而是每次增1;当发生丢包或者超时,cwnd重新设置为1且进入慢启动状态。
四、UDP连接
4.1无连接运输
UDP协议只做了运输层协议中能够做的最少的工作,因为除了多路复用/分解以及少量的差错检测外,该协议几乎未对IP协议增加其他东西。故执行一个UDP协议时,无须进行任何运输层的握手,主机端UDP为报文段增加首部字节,然后封装进网络层的IP数据报,将其发送给服务端。
相对于TCP连接,UDP也许没有更多的功能,但是它也有一定的作用:①不需建立连接,一方面节省了建立连接的时间,另一方面不需像TCP连接一样分配缓存和变量,一定程度上减轻了服务端压力;②分组的头部开销较少,一个TCP报文段首部需20字节,而UDP报文段首部仅需8字节;③无拥塞控制协议(为TCP独有,后文会讲到),能更好地控制发送报文的时间和速度。
4.2 UDP检验和
上文提到过,UDP协议有少量的差错检测,当发送方的UDP报文到接收方过程中发生了比特字的丢失或改变,则将会在接收方检测出来,这就是UDP检验和功能。
举个例子,假如发送方发送的报文段内容为0110011001100000的16比特字,则取它的反码1001100110011111封装进报文段的检验和部分,在接收方,将该比特字和检验和加在一起,若在传输过程中没有引入差错,则此时该显示的是1111111111111111,若这些比特中出现0,那么在传输过程中就出现了差错。
鉴于运输层知识点较多,下节我将会对运输层章节的内容做一个总结,以及详细介绍TCP协议中的三次握手,四次挥手的过程,欢迎大家持续关注。
链接如下:
计算机网络-运输层 三次握手和四次挥手