第六章 传输层

传输层的必要性

既然网络层已把源主机上发出的数据包传送给了目的主机,那么为什么还需要设置一个传输层呢?

位于两台网络主机间的真正数据通信主体不是这两台主机,而是两台主机中的各种网络应用进程。因为在同一时刻,两主机间可以进行多个应用通信。
而这里的应用进程识别就要依靠“传输层”了,它就是通过“端口”将不同应用进程进行对应的。

传输层服务

(1)面向连接服务

在提供传输服务前需要先建立专门的传输连接,而且这条连接是可管理的,在需要或通信结束时进行拆除。面向连接的传输服务是可靠的传输服务,而且可提供拥塞控制和差错控制功能,如TCP提供的传输服务。

(2)无连接服务

在提供服务前不需要建立专门的传输连接,直接向目的节点发送数据,不管是否有可传输的通道,只提供不可靠(仅做尽力传输)的传输服务,如UDP提供的传输服务。

上述服务与网络层提供的面向连接和无连接服务很像,但网络层是通信子网的一个组成部分,网络服务质量并不可靠,如频繁地丢失分组,网络层系统可能崩溃或不断地进行网络复位。对于这些情况,用户将束手无策,因为用户不能对通信子网加以控制。而传输层能对通信子网进行管理和控制。

释放连接

(1)对称释放

连接的两个方向彼此独立,每个方向需要单独被释放。当一方调用Disconnect原语时,意味着它不再需要发送数据了,但它仍然希望能接收对方发过来的数据。在这种方式中,只有在双方都调用了Disconnect原语,各自向对方发送DR TPDU后一个传输连接才可能被真正释放出来。

(2)非对称释放

任何一方都可以调用Disconnect原语,在本端传输实体向对端发送一个DR TPDU后双向传输连接都将被释放。


差错控制

七层模型中提供差错控制的有:

  • 数据链路层
  • 网络层
  • 传输层

每一层的校验只校验本层的数据,传输层是段,网络层是包,链路层是帧。

数据链路层

数据链路层FCS是为了防止网卡软硬件bug、电缆不可靠、信号干扰而造成信号失真、数据错误。如果不检查,将一直到达目的地主机,很有可能TCP/UDP层才会校验出错误,这显然不合理。
数据链路层的差错检测的目的是做到”无比特差错”。使用循环冗余检验CRC差错检测技术
无法管帧丢失、失序、重复,它只负责一个帧要是传对了,就是对的

  • 两种方式
    • 对于通信质量良好的有线传输链路,数据链路层协议不采用确认和重传机制,不要求数据链路层向上提供可靠的传输。如果在数据链路层出现了差错就靠上层协议来完成改正差错的任务
    • 对于通信质量较差的无线传输链路,数据链路层协议使用确认和重传机制,数据链路层向上提供可靠的传输服务。现在的通信线路的质量已经大大提高,由通信质量不好而产生差错的概率已经大大降低。

网络层

网络层的校验只用于针对网络层的头部
好比货车司机只管车,车跑的好他就放心了。车上箱子里的水果零食坏没坏不关他的事。箱子里的水果坏没坏是传输层的事。
数据包到了路由器之后,路由器会把这个数据包拆开,根据下一跳的地址,设置新的链路层头部的目的地址,crc校验值,IP首部的的ttl值,甚至可能还会对数据包进行分片,这样修改的更多了,如果在路由器处理的过程中这个数据出错,那么链路层的校验是发现不了错误的。

传输层

运输层的差错检测的目的是做到”无传输差错”。即弥补帧丢失、帧重复、帧失序。

最大最小流公平原则

想象一下把水倒进网络中:

1.所有流量以0速率开始
2.增加流量,直到网络中出现阻塞
3.固定阻塞流的速率
4.转到步骤2查看所有剩余的流,重复上述步骤再次增加流量

例题
例题
例题

AIMD

公平性和收敛性

为什么要收敛和公平?TCP不是传输可靠、够快就行了吗?

远远不够,因为TCP是端到端的,窗口增减也是试探性的“自适应”方式,网络是黑盒,这就有很多问题。你自己一个人发包发得快,侵略性强,没有太大问题。但是如果其他人也跟你一样没有节制的发包呢?这就会造成网络负载过重,以至于崩溃。公平性和收敛性的出发点就在这里。让每一个TCP发送端尽可能地均分带宽,同时减少丢包,减轻网络设备的压力。这其实是很难的trade off。TCP窗口总是锯齿状地周期抖动,增长-减小,不断循环,这种探测带宽的行为一定会造成丢包,只是或多或少的差别而已。

为什么AIMD会收敛

现在普遍的减窗策略是“乘性减窗”,英文对应“MD”。比如你们固有的带宽是8M,一开始你自己全占了,然后同学开始抢,慢启动发包很快,于是,交换机缓存扛不住了,丢包了。这时候你的吞吐率是7M,同学的速率是1M。你们两个的TCP察觉到丢包后,把速率各减去一半,你有3.5M,他有0.5M。网络不拥塞了,没有丢包,那就继续增窗。该增多少呢?你的带宽明显占优势,同学有没有可能获得比你更高的速率呢?怎么样增才能达到均分带宽的目的?现在普遍的增窗策略是“加性增窗”,英文对应“AI”。也就是每条TCP连接在一个RTT内的增量是常数,假设这个加性因子为200K。那接下来的速率增长就是:你有3.5+0.2=3.7,同学有0.5+0.2=0.7.

看到这里,或许有的人就恍然大悟了:这样增窗,结果是大家的速率都收敛。也许还有人不明白,那就把速率随时间变化的情况列出出来:

3.5     0.5
3.7     0.7
3.9     0.9
4.1     1.1
……………………………
5.5     2.5
2.75    1.25    MD
……………………………
4.75    3.25
2.375   1.625   MD
……………………………
4.375   3.625
2.1875  1.8125  MD
……………………………
4.1875  3.8125  MD
…………………………… 

从以上速率变化,可以看出,两条TCP连接的速率在逐渐趋近,这就是AIMD策略的效果:收敛,到最后公平。

MIMD,AIAD

AIMD

TCP

TCP报文

TCP报文

(1)URG
Urgent Pointer(紧急指针)控制位,指出当前数据段中是否有紧急数据,占1位,置1时表示有紧急数据。紧急数据会优先安排传送,而不会按照原来的排队顺序进行发送。仅当本字段的置1,后面的“紧急指针”字段才有意义。

(2)ACK
Acknowledgement(确认)控制位,指示TCP数据段中的“确认号”字段是否有效,占1位。仅当ACK位置1时才表示“确认号”字段有效,否则表示“确认号”字段无效,应用层实体在读取数据时可以不管“确认号”字段。

(3)PSH
Push(推)控制位,指示是否需要立即把收到的该数据段提交给应用进程,占1位。当PSH位置1时要求接收端尽快把该数据段提交给应用进程,而置0时没这个要求,可以先缓存起来。

(4)RST
Reset(重置)控制位,用于重置、释放一个已经混乱的传输连接,然后重建新的传输连接,占1位。当RST位置1时,释放当前传输连接,然后可以重新建立新的传输连接。

(5)SYN
Synchronization(同步)控制位,用来在传输连接建立时同步传输连接序号,占1位。当SYN位置1时,表示这是一个连接请求或连接确认报文。当SYN=1,而ACK=0时,表明这是一个连接请求数据段。如果对方同意建立连接,则对方会返回一个SYN=1、ACK=1的确认。

(6)FIN
Final(最后)控制位,用于释放一个传输连接,占1位。当FIN位置1时,表示数据已全部传输完成,发送端没有数据要传输了,要求释放当前连接,但是接收端仍然可以继续接收还没有接收完的数据。在正常传输时,该位置0。

MSS(Maximum Segment Size,最大报文长度)

MSS是TCP协议定义的一个选项,用于在TCP连接建立时,收发双方协商通信时每一个报文段所能承载的最大数据长度

在以太网环境下,MSS=MTU-20字节TCP报头-20字节IP报头,MSS值一般就是1500-20-20=1460字节。

如果一台主机没有使用这个选项,那么它默认可以接受536字节的有效载荷

TCP连接建立

TCP连接建立

TCP连接释放

TCP连接释放

TCP确认机制

(1)TCP可一次连续发送多个数据段

一次性连续发送多个数据段,这样可大大提高数据发送效率。但一次性可发送多少个数据段是受对方返回的“窗口大小”字段值和当前可用“发送窗口”大小双重限制的。因为发送端对还没有收到确认的数据段要进行缓存,这需要占用一定的“发送窗口”大小。

(2)仅对连续接收的数据段进行确认

返回的确认数据段中的“确认号”字段值仅代表对端已正确接收的连续数据段(最高字节序号+1),而不一定是已正确接收数据段中的“最高序号+1”,因为中间可能还有些数据段因为网络延迟而暂时未收到,或出现了传输错误而丢失了。

(3)不连续序号的数据将先缓存

当主机接收到的数据段序号不连续时,不连续部分不会向应用层的应用进程进行提交,而是先缓存在“接收窗口”中,等待接收到中断的序号的数据段后再一起提交。

TCP的超时重传机制

“超时重传”是TCP保证数据可靠性的另一个重要机制,其原理是在发送某一个数据段以后就开启一个超时重传计时器(Retransmission Timer,RTT)。如果在这个定时器时间内没有收到来自对方的某个数据段的确认,发送端启动重传机制,重新发送对应的数据段,直到发送成功为止。

要注意的是,并不是RTT定时器一到,就会立即重传数据,毕竟从“发送窗口”缓存中找到对应的数据段,然后安排重新发送都是需要时间的,实际上,超时重发的时间间隔(Retransmission Time Out)要大于RTT值。

SRTT的计算

RTT值不是固定的,所以就出现了平滑RTT(SRTT)的概念,就是在充分考虑历史RTT值的情况下所设计的一个RTT值计算公式。

SRTT(新的SRTT)=αSRTT(旧的SRTT值)+(1-α)RTT(新的RTT样本值)

SRTT的初始值就是第一个RTT值。这里的α是一个平滑因子,它决定了旧的SRTT值所占的权重,0≤α<1。

RTO的计算

正常情况下,TCP使用β SRTT作为重传超时间隔(β>1),而且最初的值总为2(也就是在两倍SRTT时间后还没收到对应数据段的确认才重传该数据段)。

在1988年,Jacobson提出使用平均偏差作为标准偏差(就是β SRTT)的新估计算法,要求维护另一个被平滑的偏差RTTD。当一个确认数据段到达时,可以得出SRRT和新的RTT样本值之间的偏差RTTD=|SRTT-RTT|。第一次测量时,RTTD为测量到的RTT样本值的一半,在以后的测量中按照以下公式进行计算:

RTTD(新的RTTD)=αRTTD(旧的RTTD)+(1-α)×|SRTT-RTT|

并且将超时重传时间设置为:

RTO=SRTT+4×RTTD

在计算加权平均RTT时,只要数据段被重发了,就不采用其往返时间作为计算SRTT和RTO的样本,这样得出的加权平均SRTT值和RTO值比较准确。

TCP的选择性确认机制

如果在重传定时器超时后仍没收到一个数据段的确认,则可能会重传对应序号后面的所有数据段,因为后面的这些数据段均暂时不会被确认,这明显大大降低了TCP数据传输性能。

为了避免这种现象的出现,在RFC3517中出现了一种称为“选择性确认”(SACK)的机制,就是在TCP数据段格式的头部“可选项”字段中添加一个代表支持SACK的选项。但这个选项在不同的数据段中有不同的字段名称和不同的含义。

假设接收端已收到1、101、201、401、501这五个序号的数据段,在发送确认号为301的确认数据段时,在SACK扩展选项中标记401(起始序号为401,结束序号为500)和501(起始序号为501,结束序号为600)这两个不连续的数据段。这时发送端就会知道,不需要再发送401和501这两个数据段了,只需发送301号数据段即可。这样大大节省了网络资源,也提高了数据传输效率。

TCP流量控制

一般说来,我们总是希望数据传输得更快一些。但如果发送方把数据发送得过快,接收方就可能来不及接收,这就会造成数据的丢失。

流量控制(flow control)就是让发送方的发送速率不要太快,既要让接收方来得及接收,也不要使网络发生拥塞。

利用滑动窗口机制可以很方便地在 TCP 连接上实现流量控制。

持续计时器:

TCP 为每一个连接设有一个持续计时器。
只要 TCP 连接的一方收到对方的零窗口通知,就启动持续计时器。
若持续计时器设置的时间到期,就发送一个零窗口探测报文段(仅携带 1 字节的数据),而对方就在确认这个探测报文段时给出了现在的窗口值。
若窗口仍然是零,则收到这个报文段的一方就重新设置持续计时器。
若窗口不是零,则死锁的僵局就可以打破了。

基于传输效率的考虑:

在一些交互式应用中,每次传输的数据部分可能仅一个或几个字节,如果为每个这样的数据传输一次,显然传输效率是很低的,因为使用几十个协议头而最终传输的有用数据却仅几个字节。这类情况还会在发送确认数据段时经常发生,如果仅是用来确认的数据段,里面的数据量是非常小的,也正因如此,所以通常是在捎带大量数据的数据段中把ACK字段置1,同时起到确认的作用。

可以用不同的机制来控制 TCP 报文段的发送时机:

  • 第一种机制是 TCP 维持一个变量,它等于最大报文段长度 MSS。只要缓存中存放的数据达到 MSS 字节时,就组装成一个 TCP 报文段发送出去。
  • 第二种机制是由发送方的应用进程指明要求发送报文段,即 TCP 支持的推送(push)操作。
  • 第三种机制是发送方的一个计时器期限到了,这时就把当前已有的缓存数据装入报文段(但长度不能超过 MSS)发送出去。

糊涂窗口综合征SWS(Silly Window Syndrome)

当数据以大块形式被传递给发送端TCP实体,但是接收端的交互式应用每次仅读取一个字节数据。

延迟确认

接收方收到数据包以后如果暂时没有数据要发给对端,它可以等一段时再确认。如果这段时间刚好有数据要传给对端,Ack就随着数据传输,而不需要单独发送一次Ack。如果超过时间还没有数据要发送,也发送Ack,避免对端以为丢包。

Nagle算法

当数据每次以很少量方式进入到发送端时,发送端只是发送第一次到达的数据字节,然后将其余后面到达的字节缓冲起来,直到发送出去的那个数据包被确认;然后将所有缓冲的字节放在一个TCP段中发送出去,并且继续开始缓冲字节,直到下一个段被确认。

Nagle算法要求,一个TCP连接在任意时刻,最多只能有一个没有被确认的小段。所谓“小段”指的是小于MSS的数据块,“没有被确认”指的是一个数据块发送出去后,没有收到对方发送的ACK确认该数据已收到。

Nagle算法就是为了尽可能发送大块数据,避免网络中充斥着许多小数据块。

Clark的解决办法

禁止接收端发送只有1个字节的窗口更新段。它强制接收端必须等待一段时间,直到有了一定数量的可用空间之后再通告给对方。特别是,只有当接
收端能够处理它在建立连接时宣告的最大数据段,或者它的缓冲区一半为空时(相当于两者之中取较小的值),它才发送窗口更新段。

TCP拥塞控制


拥塞控制和流量控制不同,拥塞控制是指TCP通过控制数据传输速率防止因数据过多造成网络阻塞。TCP规定发送方不仅要维护一个拥塞窗口,这个拥塞窗口的大小是发送方根据网络拥塞情况进行判断从而确定的。所以发送方发送速率不仅取决于接收窗口的大小,也取决于拥塞窗口的大小,发送上限取这两个窗口的较小值。
TCP维护拥塞窗口的算法主要包括四个:慢启动、拥塞避免、快速重传和快速恢复。

慢开始门限 ssthresh 的用法如下:
当 cwnd < ssthresh 时,使用慢开始算法。
当 cwnd > ssthresh 时,停止使用慢开始算法而改用拥塞避免算法。
当 cwnd = ssthresh 时,既可使用慢开始算法,也可使用拥塞避免算法。
拥塞避免算法的思路是让拥塞窗口 cwnd 缓慢地增大,即每经过一个轮次就把发送方的拥塞窗口 cwnd 加 1,而不是加倍,使拥塞窗口 cwnd 按线性规律缓慢增长。

  • 慢启动
    慢启动的“慢”不是指拥塞窗口cwnd的发送速率慢,而是TCP在初始设置的拥塞窗口较小,慢慢增大进行网络拥塞试探。算法最初设置窗口大小cwnd=1,每次接收到一个确认报文段后,都会将窗口值加一。于是一次往返延迟时间(RTT)以后,接收方对那个报文进行确认,拥塞窗口cwnd=2。再经过一次RTT以后,接收方对两个报文进行确认,cwnd=4。以此类推,我们可以发现,拥塞窗口大小是呈指数增长的,这印证了前面说的慢启动的“慢”不是发送速率慢。当拥塞窗口超过了一个阈值ssthresh之后,开始使用拥塞避免算法。
  • 拥塞避免
    拥塞控制算法的思想是当慢启动使拥塞窗口大小达到阈值ssthresh时,每次经过一个RTT时,窗口大小增加1,而不是像慢启动一样,每次都是成倍增长。当出现一次拥塞时,将阈值ssthresh设置成为当前拥塞窗口cwnd的大小的一半(但阈值不能小于2)。然后拥塞窗口cwnd重新设置为1,重新进行慢启动算法。

拥塞控制
从上图可以看出当窗口cwnd达到24时,出现网络拥塞,阈值ssthresh被降为此时cwnd的一半即为24,并重新进入慢开始阶段。

  • 快速重传。 一旦接收方收到了失序的报文,立马发送一个ACK给发送方。当发送方收到三个同样的ACK报文时,就可以认为发生了丢包,需要进行重传。
  • 快速恢复。 快速恢复的思想是一旦发送方接受到三个重复的ACK报文时,将阈值ssthresh设置为当前拥塞窗口cwnd的一半,然后跳过慢开始的步骤,直接将拥塞窗口的值设置为ssthresh,使拥塞窗口大小线性增加。

UDP

UDP是一种无连接传输层协议,不像TCP那样需要服务器监听,也不必等待客户端与服务器建立连接后才能通信,当然,最后能否把数据传输成功,UDP是不能保证的。

UDP具有以下几个方面的明显特性:

(1)无连接性

在使用UDP进行数据传输前是不需要建立专门的传输连接的,当然,在数据发送结束时也无须释放连接了。

(2)不可靠性

因为UDP传输数据时是不需要事先建立专门的传输连接的,所以它的传输是不可靠的(但会尽最大努力进行交付)

(3)以报文为边界

UDP直接对应用层提交的报文进行封装、传输,但不拆分,也不合并,保留原来报文的边界。因此,UDP是消息流,而TCP是字节流。因为UDP不拆分报文,自然也就没有报文段之说,但UDP报文传输到网络层后,在网络层仍然可以根据网络的MTU值进行分割。

(4)无流量控制和拥塞控制功能

使用UDP进行数据传输时不能进行流量控制和拥塞控制,因为这类数据传输的连续性要比数据的完整性更重要,允许数据在传输过程中有部分丢失,如IP电话、流媒体通信等。

(5)支持各种交互通信方式

TCP不支持组播、广播通信方式,只支持一对一的单播方式,但UDP支持各种通信方式,即可以是一对一、一对多、多对一和多对多的方式。

计算机网络中有许多使用UDP的应用服务,如DNS、SNMP、DHCP和RIP等。