现在网络上大部分的网络请求都是以TCP的方式进行传输的了。网络链路是固定的,各种链路情况也是不一样的。网络拥堵一直是TCP协议设计和使用的时候尽力要避免的。比如,从TCP协议的网络包协议设计来看,TCP使用一发一答的ACK的网络包确认方式,而不是使用NAK这种会增加确认包的方式来做确认机制。这个就是在尽力降低网络上的包传递数量,避免网络拥堵。
还有哪些控制网络拥堵的方式呢?
慢启动当一个连接连接上网络的时候,并不应该一次向网络中就发送大量的数据包,否则的话,如果网络链路状况不是很好的情况,这些网络包可能会加重网络拥堵的情况。所以最初TCP连接建立之后,发送网络包的大小是逐渐增长的,最开始是1个最大报文大小,然后是指数级增长。这个就是慢启动机制。
但是到了一个数值,就不能再进行指数增长了,这个时候,网络包增长就从指数增长改成线性增长,就是一次增加一个MSS。这个就是拥塞避免阶段。
Nagle算法如果互联网上传递的都是小包,那绝对是个灾难,每个网络请求都耗费比较大的资源,如果一份数据分为零零散散很多份小包,每个网络传输都只传输一个小包,那么是典型的浪费资源,增加拥堵。糊涂窗口综合症就是发送方和接收方糊里糊涂达成的协商是传送小包。
为了解决这个问题,很多方法应运而生,Nagle算法就是其中一个方法。
Nagle算法规定了,发送方网络链路上一个连接只能有一个未获得ACK的请求包。这个就意味着,发送方只有等待上一个请求的ACK回来之后才能发送下一个请求,这样两个请求过程中间,发送方的缓存区就存储了足够滑动窗口大小的包进行传递,这样就有效避免了大量的小包产生。
Cork算法另外一种解决糊涂窗口综合症的方法就是Cork算法。这个算法比Nagle算法更激进一些,干脆直接计算出一个值,当发送方的滑动窗口大小小于这个值的时候,不进行数据包的发送。这样这个算法就能有效直接杜绝小包的出现了。当然可能会导致数据有一定的延迟性了。
Nagle和Cork算法都是在发送方进行控制,两个算法的着重点不同,Cork算法着重点在于避免小包,更多是端到端的优化。Nagle算法则是为了提高网络的利用率。
延迟ACK从接收方也有能力防止糊涂窗口综合症。延迟ACK算法就是接收方并不是收到请求之后立刻发送ACK,而是开启一个计时器,等到计时器结束的时候,才发送ACK。或者是接收方在需要回发送请求的时候,顺带着把上个请求的ACK发送回去了。这个机制如果配合Nagle算法,能让连接的滑动窗口达到一个预期的比较好的值。
重传机制上面都是防止阻塞的方法,但是万一阻塞了呢?发出去的请求包在规定时间内没有收到ACK,不管是请求包丢失,还是ACK包丢失,还是网络延迟,总之,这里都是需要有个重传机制的。TCP的重传机制有两种:超时重传和快速重传。
超时重传说白了就是在请求包发出去的时候,开启一个计时器,当计时器达到时间之后,没有收到ACK,则就进行重发请求的操作,一直重发直到达到重发上限次数或者收到ACK。
快速重传还有一种机制就是快速重传,当接收方收到的数据包是不正常的序列号,那么接收方会重复把应该收到的那一条ACK重复发送,这个时候,如果发送方收到连续3条的同一个序列号的ACK,那么就会启动快速重传机制,把这个ACK对应的发送包重新发送一次。具体可以参考: