目錄
- 前言
- 1. TCP的超時重傳機制
- 2. TCP的流量控制機制
- 3. TCP的滑動窗口機制
- 4. TCP的擁塞控制機制
- 5. TCP的延遲應答機制
- 6. TCP的捎帶應答機制
- 7. 總結以及思考
前言
強烈建議先看傳輸層協議詳解(上)后再看這篇文章. 上一篇文章講到TCP協議為了保證可靠性而做的一些策略, 這篇文章會深度解析剩下的策略.
1. TCP的超時重傳機制
主機 A 發送數據給 B 之后,可能因為網絡擁堵等原因,數據無法到達主機 B;如果主機 A 在一個特定時間間隔內沒有收到 B 發來的確認應答,就會進行重發。這種操作叫做 超時重傳。
就是我收到ACK,對方收到數據,但是,我沒有收到ACK,對方沒有收到數據.
不管是數據丟了,還是應答丟了,發送方的策略都是超時之后進行補發.
那么就有下面兩個問題:
1.應答丟包后,發送方進行補發,那接收方就有兩個一樣的報文了,怎么去重呢?
一樣的報文,說明32位序號是一樣的,所以序號也有去重的功能!
并且,如果有不同的多個報文,序號也可以用來排序,使之按序到達.
2.那么,超時的時間如何確定?
這個時間的長短,隨著網絡環境的不同,是有差異的.
如果超時時間設的太長,會影響整體的重傳效率;
如果超時時間設的太短,有可能會頻繁發送重復的包。
2. TCP的流量控制機制
接收端處理數據的速度是有限的.如果發送端發的太快,導致接收端的緩沖區被打滿,
這個時候如果發送端繼續發送,就會造成丟包,繼而引起丟包重傳等等一系列連鎖反應。
因此TCP支持根據接收端的接收能力,來決定發送端的發送速度,這個機制就叫做流量控制.
通過下面的若干個問題進行講解:
- 接收方的接受能力是什么?
可以認為是: 接受緩沖區中剩余空間的大小!
- 發送方怎么知道對方的接受能力是多少?
發送方每次發送報文給接收方,接收方都會返回ACK應答,就是一個報頭,此時接收方會把自己的剩余空間填入 16位窗口大小 這一字段,再返回給發送方!
- 那雙方第一次發送信息的時候呢,又沒有ACK應答,怎么控制?
三次握手期間,已經協商交換過了雙方的接受能力!
- 16位窗口大小表示的數字最大是65535,那么 TCP 窗口最大就是 65535 字節么?
實際上,TCP首部40字節選項中還包含了一個窗口擴大因子M,實際窗口大小是窗口字段的值左移 M 位。
- 接收方的剩余空間為0了,發送方會等待,那過后接收方又有空間了,發送發送方怎么及時知道?
接收方會給發送方傳遞"窗口更新通知",其實就是一個報文,或是發送方間隔進行"窗口探測",也是一個報文。這兩種方式一般是同時使用的。
- 那如果對方一直不進行窗口更新呢?
就要用到報頭里的另一個標記位:PSH.就是告訴對方把緩沖區里的數據趕快取走.
當然,如果我們想讓對方盡快處理數據,都可以設置PSH,不一定非要是0的時候.
這里再來講一下最后一個標記位URG和16位緊急指針這個字段:
URG: 緊急指針標記位.URG置為0時,報頭里的 16位緊急指針 這一字段無意義,置1時,才有意義.
16位緊急指針: 標識哪部分數據是緊急數據.
所以在流量控制機制中,我們學習了以下幾個字段:
- 16位窗口大小
- PSH標記位
- URG標記位
- 16位進階指針
3. TCP的滑動窗口機制
上篇文章中講到, 服務器每收到一次數據都會回一個ACK確認應答. 但是這樣是不是效率有點低下了?由其是數據往返時間比較長的時候. 有沒有什么方法可以一次性發送多條數據呢? 當然TCP協議也考慮到了這一點:
滑動窗口:
可以將發送緩沖區想象成一個數組, 滑動窗口的本質就是此數組中的兩個元素下標, 這兩個下標會維護一段數據, 我們就可以將這份維護的數據一次性發給對方, 能大大的提高效率.
- 窗口大小指的是無需等待確認應答而可以繼續發送數據的最大值. 上圖的窗口大小就是4000個字節(四個段).
- 發送前四個段的時候, 不需要等待任何ACK, 直接發送;
- 收到第一個ACK后, 滑動窗口向后移動, 繼續發送第五個段的數據; 依次類推;
- 操作系統內核為了維護這個滑動窗口, 需要開辟 發送緩沖區 來記錄當前還有哪些數據沒有應答; 只有確認應答過的數據, 才能從緩沖區刪掉;
- 窗口越大, 則網絡的吞吐率就越高;
所以下面兩個問題就有了答案:
(1)根據流量控制機制發送方已經知道了對方的接收能力,那具體該如何發送?
流量控制,就是通過滑動窗口實現的!
(2)在超時重傳時,超時時間以內,已經發送的報文不能被丟棄,而是要保存起來!保存在哪里?
保存在滑動窗口中!
4. TCP的擁塞控制機制
雖然是TCP有滑動窗口這一大殺器來提高效率和可靠性, 但是我們始終在關心的是, 對端怎么怎么樣, 對端的接受能力怎么樣, 對端是否收到了信息. 我們從來沒有考慮過網絡本身的情況, 萬一網絡本身就不好, 還一次性發送了大量數據, 丟包了怎么辦? . 當然這一切都在TCP協議的預料之中.
擁塞控制:
因為網絡上有很多的計算機, 可能當前的網絡狀態就已經比較擁堵. 在不清楚當前網絡狀態下, 貿然發送大量的數據,是很有可能引起雪上加霜的. TCP引入 慢啟動 機制, 先發少量的數據, 探探路, 摸清當前的網絡擁堵狀態, 再決定按照多大的速度傳輸數據.
其實你只用知道, TCP的擁塞控制是用來關心當前網絡狀態的, 并且它采用的慢啟動機制, 雖然這其中還有很多細節可以挖掘, 但是作為從事后端開發的大學生而言, 學到這個地方已經是有點東西了.
(有興趣的同學可以看看下面對"慢啟動"的的圖像以及一點理解)
5. TCP的延遲應答機制
若接收數據后立刻返回ACK應答, 返回窗口會比較小.
- 假設接收端緩沖區為1M. 一次收到了500K的數據; 如果立刻應答, 返回的窗口就是500K;
- 但實際上可能處理端處理的速度很快, 10ms之內就把500K數據從緩沖區消費掉了;
- 在這種情況下, 接收端處理還遠沒有達到自己的極限, 即使窗口再放大一些, 也能處理過來;
- 如果接收端稍微等一會再應答, 比如等待200ms再應答, 那么這個時候返回的窗口大小就是1M;
一定要記得, 窗口越大, 網絡吞吐量就越大, 傳輸效率就越高. 我們的目標是在保證網絡不擁塞的情況下盡量提高傳輸效率;
說白了, 有時候立刻應答并不是一種高效率的體現.
6. TCP的捎帶應答機制
捎帶應答機制其實就是: ACK應答+數據 一起返回去.
要注意的是: 三次握手里的前兩次握手是不能捎帶應答的,因為此時連接還沒有建立好,只有建立成功了才可以通信.但是第三層握手ACK可以捎帶數據了.
至此,TCP協議報頭里的所有重要字段及其它們的作用機制都講解完畢!
7. 總結以及思考
現在再來看, TCP是面向字節流的就大概能理解了. TCP只管迅速的給對端發包, 不管一個數據要分幾次發, 一次性發多少, 總之它只管盡快將包發過去. 換句話說,就是站在TCP的角度,沒有報文的概念,所有的數據都是放在一個字符數組的緩沖區里,只是單純的把數據推送過去,但是到底有沒有推完一個,一個半…)都由網絡決定.
雖然這樣大大的提升了效率, 但是會帶來粘包問題. 也就是說對端收到數據后, 它并不知道這個數據是否是完整的一個, 還是半個, 甚至是兩個半都有可能.
TCP小結:
TCP和UDP的對比:
我們說了TCP是可靠連接,那么是不是TCP一定就優于UDP呢?
當然不是! TCP和UDP之間的優點和缺點,不能簡單,絕對的進行比較。
(1)TCP 用于可靠傳輸的情況,應用于文件傳輸,重要狀態更新等場景;
(2)UDP 用于對高速傳輸和實時性要求較高的通信領域,例如,早期的 QQ,視頻傳輸等。另外 UDP 可以用于廣播;