如果发送方发送速率过快,接收方可能来不及接收,会造成数据的丢失,降低吞吐率。
流量控制就是控制发送方的发送速率,使接收方来得及接收。
滑动窗口机制可以方便地实现TCP连接上的流量控制。接收方回送确认时,将给出自己的接收窗口,发送方根据对方的接收窗口确定自己的发送窗口,就可以实现流量控制。
在这个过程中,试想一种情况:B向A发送零窗口报文后,A等待B发送非零窗口通知;但B发送非零窗口通知时,该报文偶发丢失了。此时,A一直等待B发送非零窗口通知,而B等待A发送新的报文段;A与B循环等待,形成了死锁。
为避免死锁的出现,TCP连接设有一个持续计时器。当TCP的一方收到对方的零窗口通知,就启动持续计时器。若持续计时器到达设置的时间,就给接收方发送一个零窗口探测报文段(仅1字节)。接收方收到该报文段后,回送当前的接收窗口值。若rwnd仍为0,则持续计时器重新计时;否则,发送方就可以开始发送数据。
对于TCP,有三种不同的机制来控制TCP报文段的发送时机:
尽管有这三种机制,但报文段的发送时机控制仍然是一个复杂的问题。主要遇到的问题是:
在某些进程(如Telnet服务)中,发送方可能每接收一个字节,就会开始发送报文段。这样,一个字节的数据加上TCP报文段和IP数据报的首部,就需要发送41字节的IP数据报。在这个数据报中,有效数据仅有一个字节,传输效率极低。
为解决此问题,TCP实现广泛采用了Nagle算法,其内容为:
Negla算法可以在数据到达较快而网速较慢时,明显减少使用的网络带宽,并有效提高吞吐量。
TCP接收方的缓存已满,而应用进程每次只从缓存中读取一个字节,然后向发送方发送确认,且窗口值为1;接着发送方再发送41字节长的数据报(有效数据1字节)。这样进行下去,网络传输的效率极低,并且会导致网络性能恶化。
为解决此问题,可以让接收方等待一段时间,使其在已有足够空间容纳一个MSS报文段或已有一半的空闲缓存时,再发送确认报文,通知接收窗口的大小。
Negla算法和接收等待配合使用,可以有效提高TCP的传输效率。
计算机网路中,链路的带宽、结点的缓存和处理机等,都是网络资源。
在某个时间段,若对网络中某一资源的需求超过了该资源所能提高的可用部分,网络性能就会恶化。这种现象就是拥塞。
拥塞出现的条件: 对资源的需求 > 可用资源
若网络中多个资源同时供应不足,网络性能将明显恶化,网络的吞吐量将随着负荷的增大而迅速下降。
然而,简单地增加网络资源是不可行的。增加缓存将使得分组排队等待时间显著变长,造成大量重传;而提高处理速率,又会导致网络瓶颈转移到其它资源上。问题的实质往往是整个系统各部分不匹配。
拥塞常常趋于恶化。拥塞引起的分组重传,并不会缓解拥塞情况,反而会加剧拥塞。
拥塞控制是防止过多的数据注入到网路中,使链路和路由器不至于过载。拥塞控制所做的前提是网络能够承受现有的网络负荷。拥塞控制是一个全局性的过程。
流量控制则是点对点的通信量控制,是端到端的问题。所要做的是抑制发送端的发送速率,使接收端来得及接收。
拥塞控制和流量控制的直接结果都是放慢发送方的发送速率。
由于拥塞是一个全局的动态问题,因此拥塞控制很难设计。
网络的高速化,使得路由器容易出现缓存不够大而造成的分组丢失。但分组丢失是拥塞的结果而非原因。
拥塞控制需要代价。有时,拥塞控制本身会成为网络性能恶化甚至死锁发生的原因。必须全面衡量得失。
拥塞控制从控制理论的角度可以分为开环控制和闭环控制。
● 开环控制:设计网络时考虑拥塞有关的因素,力求网络工作时不产生拥塞。但系统一旦投入运行,就不能改动。
● 闭环控制:基于反馈环路的概念,主要有以下几种措施:
TCP采用基于窗口的方法进行拥塞控制。它属于闭环控制方法。
发送方维护一个拥塞窗口cwnd。真正的发送窗口 = min{接收方接收窗口, 拥塞窗口};
控制拥塞窗口的原则:
发生拥塞的判断:
当主机开始发送数据时,由于不知道网络的负荷情况,应当先探测,由小到大地增大拥塞窗口。
拥塞避免是让cwnd缓慢增大,尽可能晚到达拥塞。拥塞避免不是没有拥塞,只是不容易出现拥塞。
收到连续的三个重复确认后,发送方除了要立即重传之外,还判断网络没有发生拥塞,而是偶发丢失分组。
因此,不执行慢开始算法,而是快恢复算法:
即慢开始门限设为当前拥塞窗口的一半,并将拥塞窗口设为当前的慢开始门限(即自身的一半),并执行拥塞避免算法。
拥塞避免阶段,拥塞窗口线性缓慢增大,称加法增大(AI);而出现超时或三连重复ACK,就要将慢开始门限设置为拥塞窗口的一半,称乘法减小(MD)。两者合一就是AIMD算法。
综上,TCP的拥塞控制可以归纳为下图:
注意:发送方窗口不仅受拥塞窗口cwnd影响,也受接收方窗口rwnd影响。
发送方窗口上限 = min {rwnd, cwnd}。
TCP协议是面向连接的协议。其运输连接有三个阶段:
● 连接建立
● 数据传送
● 连接释放
在TCP建立连接时,需要解决三个问题:
● 双方要能够明确知道对方的存在;
● 要允许双方协商一些参数(窗口值、是否使用窗口扩大选项和时间戳选项);
● 能够对运输实体资源进行分配(缓存大小、连接表中的项目等)。
TCP连接建立采用客户端/服务器方式(C/S方式):
● 主动发起连接建立的应用进程就是客户端;
● 被动等待连接建立的应用进程就是服务器。
TCP为建立连接而发送报文段的过程,称为握手。
TCP的连接建立需要进行三次握手,即建立连接的整个过程需要发送三次报文段。
主机A运行的应用进程是客户,主机B运行的应用进程是服务器。最初,双方都处于CLOSED状态。
开始前,服务器端B已经创建传输控制模块TCB,表示准备好接受连接请求,并进入LISTEN状态,等待客户连接请求。
采用三次握手主要是为了避免建立失效的连接。
例如,当A向B发送了连接请求,而第一个连接请求由于网络原因超时;此时,由于超时,A会向B重传一次连接请求;这样,B就会收到两次连接请求,其中有一个超时的是失效的。如果出现异常状况,超时的那个连接请求在上一次连接释放后才到达。对于B,会误认为后到的那一个请求是新的连接请求,于是再次返回确认。如果不进行第三次握手,就会建立一个失效的连接。这时B会认为连接已建立,而等待A发送数据;但A没有发送请求,收到确认并不会作出回应,B的资源也就浪费了。
而采用了三次握手后,即使发生上述情况,B无法收到A的确认,就会知道没有建立连接,避免了资源的浪费。
TCP为释放连接而发送报文段的过程,称为挥手。
TCP的连接释放需要进行四次挥手,即释放连接的整个过程需要发送四次报文段。
数据传输结束后,TCP连接的双方都可以释放连接。这里假设A开始释放连接。释放前,双方均处于ESTABLISH状态。
A必须等待时间等待计时器设置的2MSL(最长报文段寿命)的时间。主要是为了:
● 保证A发送的最后一个ACK报文能够到达B,如果没有到达(丢失或超时),B会进行重传FIN+ACK报文,而A能够在2MSL的时间内收到重传(在0~MSL内重传,2MSL前到达),这样A就能重传一次ACK报文,并重启时间等待计时器。若是没有等待时间,A就无法收到B的重传,也不会重传给B,B就无法正常地释放连接。
● 防止已失效的连接请求报文段出现。经过2MSL的时间后,能够确保本连接持续时间内所有的报文段都消失(丢弃),保证下一次新的连接时,不会出现旧的报文段(都因超时丢弃)。
另外,TCP设有保活计时器。当建立连接后,一方的主机突然出现故障,另一方就不再能收到传来的数据。为了不让资源白白浪费,使用保活计时器判断连接的有效性。每当收到对方传来的数据,就将保活计时器重置。若到达设置的时间限制(通常为2小时),就发送一个探测报文段,之后每隔75秒发送一次。若10个探测报文后,对方仍没有回应,就认为对方发生故障,关闭这个TCP连接。
为了清晰地表示TCP连接地各种状态的联系,下面给出TCP连接的有限状态机。
图中每一个方框就是TCP连接的一个可能状态。方框内的英文就是TCP标准使用的连接状态名。
状态间的箭头表示可能发生的状态变迁。箭头旁的字表示变迁发生的原因。
粗实线箭头表示客户进程的正常变迁,粗虚线箭头表示服务器进程的正常变迁。细线箭头表示异常变迁。