計(jì)算機(jī)網(wǎng)絡(luò)中的帶寬、交換結(jié)點(diǎn)中的緩存和處理機(jī)等,都是網(wǎng)絡(luò)的資源。在某段時(shí)間,若對(duì)網(wǎng)絡(luò)中某一資源的需求超過了該資源所能提供的可用部分,網(wǎng)絡(luò)的性能就會(huì)變壞。這種情況就叫做擁塞。
擁塞控制就是防止過多的數(shù)據(jù)注入網(wǎng)絡(luò)中,這樣可以使網(wǎng)絡(luò)中的路由器或鏈路不致過載。和流量控制不同,擁塞控制是一個(gè)全局性的過程,而流量控制是點(diǎn)對(duì)點(diǎn)通信量的控制。
慢啟動(dòng)算法與擁塞避免算法
擁塞避免算法的前提是:假定由于分組受到損壞引起的丟失是非常少的,因此分組丟失(發(fā)生超時(shí)和接收到重復(fù)的確認(rèn))就意味著在源主機(jī)和目的主機(jī)之間的某處網(wǎng)絡(luò)發(fā)生了擁塞
慢啟動(dòng)算法為發(fā)送方的TCP增加了另一個(gè)窗口:擁塞窗口,記為cwnd。
與另一個(gè)網(wǎng)絡(luò)的主機(jī)建立TCP連接時(shí),擁塞窗口被初始化為1個(gè)報(bào)文段(即另一端通告的報(bào)文段大小),每收到一個(gè)ACK,擁塞窗口就增加一個(gè)報(bào)文段。
實(shí)現(xiàn)
為了防止cwnd增長過大引起網(wǎng)絡(luò)擁塞,還需設(shè)置一個(gè)慢開始門限ssthresh狀態(tài)變量。
ssthresh 的用法如下:
- 當(dāng)cwnd < ssthresh時(shí),使用慢開始算法。
- 當(dāng)cwnd > ssthresh時(shí),改用擁塞避免算法。
- 當(dāng)cwnd = ssthresh時(shí),慢啟動(dòng)與擁塞避免算法任意。
無論是在慢開始階段還是在擁塞避免階段,只要發(fā)送方判斷網(wǎng)絡(luò)出現(xiàn)擁塞(其根據(jù)就是沒有收到確認(rèn)ACK,雖然沒有收到確認(rèn)可能是其他原因,但是因?yàn)闊o法判定,所以都當(dāng)做擁塞來處理),就把慢開始門限設(shè)置為出現(xiàn)擁塞時(shí)的發(fā)送窗口大小的一半。然后把擁塞窗口設(shè)置為1,執(zhí)行慢開始算法。
快速重傳算法
超時(shí)重傳是TCP協(xié)議保證數(shù)據(jù)可靠性的一個(gè)重要機(jī)制,其原理是在發(fā)送一個(gè)數(shù)據(jù)以后就開啟一個(gè)計(jì)時(shí)器。在一定時(shí)間內(nèi)如果沒有得到發(fā)送數(shù)據(jù)報(bào)的ACK報(bào)文,那么就重新發(fā)送數(shù)據(jù),直到發(fā)送成功為止。
這是數(shù)據(jù)包丟失的情況下給出的一種修補(bǔ)機(jī)制。一般來說,重傳發(fā)生在超時(shí)之后,但是如果發(fā)送端接收到3個(gè)以上的重復(fù)ACK,就應(yīng)該意識(shí)到,數(shù)據(jù)丟了,需要重新傳遞。這個(gè)機(jī)制不需要等到重傳定時(shí)器溢出,所以叫做快速重傳。
而快速重傳以后,因?yàn)樽叩牟皇锹龁?dòng)而是擁塞避免算法,所以這又叫做快速恢復(fù)算法。
- 為什么需要收到3個(gè)以上的重復(fù)ACK,才會(huì)執(zhí)行快速重傳?
在沒有快速重傳和快速恢復(fù)的算法之前,重傳依靠發(fā)送方的retransmit timeout,就在timeout內(nèi)如果沒有接收到對(duì)方的ACK,默認(rèn)包丟失,發(fā)送方就重傳。
包丟失的原因:
- 包 checksum 出錯(cuò)
- 網(wǎng)絡(luò)擁塞
- 網(wǎng)絡(luò)斷,包括路由重收斂。
但是無法判斷是 哪一種算法,于是采用最笨的方法,就是將自己的發(fā)送速率減半,即cwnd/2,這樣的方法對(duì)2是有效的。可以緩解網(wǎng)絡(luò)擁塞。
但是對(duì)于1來說,丟包是因?yàn)榕紶柍鲥e(cuò)引起的,一丟包就對(duì)半減速不合理。于是有了快速重傳算法,基于在反向還可以接收到ACK,可以認(rèn)為網(wǎng)絡(luò)并沒有斷,否則也接收不到ACK,如果在timeout時(shí)間內(nèi)沒有接收到>2的重復(fù)的 ACK,則大概率是亂序。而如果收到3個(gè)或2個(gè)以上的duplicated ACK,則大概率是丟包。