TCP/IP(五):TCP 协议详解
上一節(jié) 中講過(guò),TCP 協(xié)議是面向有連接的協(xié)議,它具有丟包重發(fā)和流量控制的功能,這是它區(qū)別于 UDP 協(xié)議最大的特點(diǎn)。本文就主要討論這兩個(gè)功能。
數(shù)據(jù)包重發(fā)
數(shù)據(jù)發(fā)送
丟包重發(fā)的前提是發(fā)送方能夠知道接收方是否成功的接收了消息。所以,在 TCP 協(xié)議中,接收端會(huì)給發(fā)送端返回一個(gè)通知,也叫作確認(rèn)應(yīng)答(ACK),這表示接收方已經(jīng)收到了數(shù)據(jù)包。
根據(jù)上一節(jié)對(duì) TCP 首部的分析得知,ACK 的值和下次發(fā)送數(shù)據(jù)包的序列號(hào)相等。因此 ACK 也可以理解為:“發(fā)送方,下次你從這個(gè)位置開(kāi)始發(fā)送!”。下圖表示了數(shù)據(jù)發(fā)送與確認(rèn)應(yīng)答的過(guò)程:
ACK 確認(rèn)
數(shù)據(jù)包和 ACK 應(yīng)答都有可能丟失,在這種情況下,發(fā)送方如果在一段時(shí)間內(nèi)沒(méi)有收到 ACK,就會(huì)重發(fā)數(shù)據(jù):
未收到 ACK 時(shí)重發(fā)數(shù)據(jù)
即使網(wǎng)絡(luò)連接正常,由于延遲的存在,接收方也有可能收到重復(fù)的數(shù)據(jù)包,因此接收方通過(guò) TCP 首部中的 SYN 判斷這個(gè)數(shù)據(jù)包是否曾經(jīng)接收過(guò)。如果已經(jīng)接收過(guò),就會(huì)丟棄這個(gè)包。
重傳超時(shí)時(shí)間(RTO)
如果發(fā)送方等待一段時(shí)間后,還是沒(méi)有收到 ACK 確認(rèn),就會(huì)啟動(dòng)超時(shí)重傳。這個(gè)等待的時(shí)間被稱為重傳超時(shí)時(shí)間(RTO,Retransmission TimeOut)。RTO 的值具體是多久呢?
首先,RTO 的值不是固定的,它是一個(gè)動(dòng)態(tài)變化的時(shí)間。這個(gè)時(shí)間總是略大于連接往返時(shí)間(RTT,Round Trip Time)。這個(gè)設(shè)定可以這樣理解:“數(shù)據(jù)發(fā)送給對(duì)方,再返回到我這里,假設(shè)需要 10 秒,那我就等待 12秒,如果超過(guò) 12 秒,那估計(jì)就是回不來(lái)了。”
RTT 是動(dòng)態(tài)變化的,因?yàn)檎l(shuí)也不知道網(wǎng)絡(luò)下一時(shí)刻是否擁堵。而當(dāng)前的 RTO 需要根據(jù)未來(lái)的 RTT 估算得出。RTO 不能估算太大,否則會(huì)多等待太多時(shí)間;也不能太小,否則會(huì)因?yàn)榫W(wǎng)絡(luò)突然變慢而將不該重傳的數(shù)據(jù)進(jìn)行重傳。
RTO 有自己的估算公式,可以保證即使 RTT 波動(dòng)較大,它的變化也不會(huì)太劇烈。感興趣的讀者可以自行查閱相關(guān)資料。
TCP 窗口
按照之前的理論,在數(shù)據(jù)包發(fā)出后,直至 ACK 確認(rèn)返回以前,發(fā)送端都無(wú)法發(fā)送數(shù)據(jù),而且包的往返時(shí)間越長(zhǎng),網(wǎng)絡(luò)利用效率和通信性能就越低。前兩張圖片形象的解釋了這一點(diǎn)。
為了解決這個(gè)問(wèn)題,TCP 使用了“窗口”這個(gè)概念。窗口具有大小,它表示無(wú)需等待確認(rèn)應(yīng)答就可以繼續(xù)發(fā)送數(shù)據(jù)包的最大數(shù)量。比如窗口大小為 4 時(shí),數(shù)據(jù)發(fā)送的示意圖如下:
窗口大小為 4
不等確認(rèn)就連續(xù)發(fā)送若干個(gè)數(shù)據(jù)包會(huì)不會(huì)有問(wèn)題呢?我們首先來(lái)看數(shù)據(jù)包丟失問(wèn)題。
我們知道 TCP 首部中的 ACK 字段表示接收方已經(jīng)收到數(shù)據(jù)的最后位置。因此,接收方成功接收到了 1-1000 字節(jié)的數(shù)據(jù)后,它會(huì)發(fā)送一個(gè) ACK = 1001 的確認(rèn)包。假設(shè) 1001-2000 字節(jié)的數(shù)據(jù)包丟失了,由于窗口長(zhǎng)度比較大,發(fā)送方會(huì)繼續(xù)發(fā)送 2001-3000 字節(jié)的數(shù)據(jù)包。接收端并不會(huì)返回這個(gè)數(shù)據(jù)包的確認(rèn),因?yàn)樗詈笫盏降臄?shù)據(jù)還是 1-1000 字節(jié)的數(shù)據(jù)包。
因此,接收端返回的數(shù)據(jù)包的 ACK 依然是 1001。這表示:“喂,發(fā)數(shù)據(jù)的,別往后發(fā)了,你第 1001 字節(jié)開(kāi)始的數(shù)據(jù)還沒(méi)來(lái)呢”。可以想見(jiàn),發(fā)送端以后每次發(fā)送數(shù)據(jù)包得到的確認(rèn)中,ACK 的值都是 1001。當(dāng)連續(xù)收到三次確認(rèn)之后,發(fā)送方會(huì)意識(shí)到:“對(duì)方還沒(méi)有接收到數(shù)據(jù),這個(gè)包需要重傳”。
因此,引入窗口的概念后,被發(fā)送的數(shù)據(jù)不能立刻丟棄,需要緩存起來(lái)以備將來(lái)需要重發(fā)。
利用窗口發(fā)送數(shù)據(jù)的過(guò)程可以用下圖表示:
快速重傳
如果是數(shù)據(jù)包沒(méi)有丟失,但是確認(rèn)包丟失了呢?這就是窗口最擅長(zhǎng)處理的問(wèn)題了。假設(shè)發(fā)送發(fā)收到的確認(rèn)包中的 ACK 第一次是 1001,第二次是 4001。那么我們完全可以相信中間的兩個(gè)包是成功被接收的。因?yàn)槿绻袥](méi)接收到的包,接收方是不會(huì)增加 ACK 的。
在這種情況下,如果不使用窗口,發(fā)送方就需要重傳第二、三個(gè)數(shù)據(jù)包,但是有了窗口的概念后,發(fā)送方就省略了兩次重傳。因此使用窗口實(shí)際上可以理解為“空間換時(shí)間”。
某些確認(rèn)包丟失時(shí)不用重發(fā)
流量控制
窗口大小
如果窗口過(guò)大,會(huì)導(dǎo)致接收方的緩存區(qū)數(shù)據(jù)溢出。這時(shí)候本該被接收的數(shù)據(jù)反而丟棄了,就會(huì)導(dǎo)致無(wú)意義的重傳。因此,窗口大小是一個(gè)可以改變的值,它由接收端主機(jī)控制,附加在 TCP 首部的“窗口大小”字段中。
慢啟動(dòng)
在連接建立的初期,如果窗口比較大,發(fā)送方可能會(huì)突然發(fā)送大量數(shù)據(jù),導(dǎo)致網(wǎng)絡(luò)癱瘓。因此,在通信一開(kāi)始時(shí),TCP 會(huì)通過(guò)慢啟動(dòng)算法得出窗口的大小,對(duì)發(fā)送數(shù)據(jù)量進(jìn)行控制。
流量控制是由發(fā)送方和接收方共同控制的。剛剛我們介紹了接收方會(huì)把自己能夠承受的最大窗口長(zhǎng)度寫(xiě)在 TCP 首部中,實(shí)際上在發(fā)送方這里,也存在流量控制,它叫擁塞窗口。TCP 協(xié)議中的窗口是指發(fā)送方窗口和接收方窗口的較小值。
慢啟動(dòng)過(guò)程如下:
以上過(guò)程可以用下圖概括:
窗口大小變化示意圖
強(qiáng)烈建議讀者對(duì)照上述八個(gè)步驟理解這幅圖!
文/bestswifter(簡(jiǎn)書(shū)作者)
原文鏈接:http://www.jianshu.com/p/d9edbba4035b
著作權(quán)歸作者所有,轉(zhuǎn)載請(qǐng)聯(lián)系作者獲得授權(quán),并標(biāo)注“簡(jiǎn)書(shū)作者”。
總結(jié)
以上是生活随笔為你收集整理的TCP/IP(五):TCP 协议详解的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: TCP/IP(四):TCP 与 UDP
- 下一篇: TCP/IP(六):HTTP 与 HTT