咱們大部分業務都創建在TCP之上,並且都通過框架層層的封裝,讓人很難看清其中的奧妙。但在和外部機構(如銀行)交互的過程當中,有不少採用的是自研的基於TCP的協議。此時沒法依賴框架,咱們就只能本身去編寫基於TCP的代碼,若是充分了解TCP的種種特性,和他們對接起來就會事半功倍。相信你們在開發TCP代碼的過程當中,也確定瞭解了粘包、長短鏈接這些概念。粘包和TCP窗口有關、長短鏈接性能優劣和TCP傳輸策略有關。這篇文章着重介紹TCP窗口。程序員
TCP發送窗口由slide_window(滑動窗口)、congestion_window(擁塞窗口)二者決定,代碼以下(4.4BSD-Lite2):面試
上面的snd_wnd、snd_una、snd_nxt三個字段組成了滑動窗口。 以下圖所示算法
發送端窗口隨時間滑動圖(不考慮重傳)例以下所示:
圖2 發送窗口隨時間滑動圖
(1)咱們一共須要發送900字節數據。可發送數據爲1-500字節,還沒有發送數據。假設首先發送400字節的數據。
(2)發送了400字節後,對端返回一個ack表示收到200序號以內的數據且窗口通告爲500。因而如圖示,窗口向前滑動了200字節。當前已發送未確認字節序號爲200-400,可發送字節序號爲401-700,假設在此還沒有發送數據。
(3)對端返回一個ack表示收到400序號內的數據且窗口通告爲400。因而如圖示,窗口向前滑動了200字節。已確認數據序號爲1-400,可發送數據爲401-800。緩存
snd_wnd此字段主要由接收端的窗口通告決定,接收端窗口通告由當前接收端剩餘多少空閒的剩餘緩存決定。以下圖所示:服務器
圖3 接收窗口通告網絡
(1)發送端:寫入2KB的數據[seq=0]。
(2)接收端:收到數據,初始化接收端緩衝區4K,寫入後還剩2K,因而通告ack[seq=2048,win=2048]。
(3)發送端:接收到窗口通告爲2048,因而最多隻能寫入2K的數據,將2K數據寫入[seq=2048]。
(4)接收端:應用層還沒有消費緩衝區。接收到2K數據後,緩衝區滿。因而通告窗口爲0,返回ack[seq=4096,win=0]。
(5)發送端:因爲發送窗口爲0,不能發送任何數據。此時發送端就須要定時的發送0字節的數據去探測接收端窗口。所需的定時器即爲持續定時器(TCPT_PERSIST)。
(6)發送端:發送0字節的探測數據。
(7)接收端:緩衝區滿,窗口通告爲0,ack[seq=4096,win=0]。
(8)發送端:繼續發送0字節的探測數據。
(9)接收端:緩衝區被應用層消費了2K,緩衝區可用字節爲2K,通告窗口爲2048,ack[seq=4096,win=2048]。
(10)發送端:繼續寫入1K的數據。框架
TCP用擁塞窗口(cwnd)來進行擁塞控制,主要利用了慢啓動、擁塞避免、快速重傳和快速恢復這四個算法。ssh
擁塞避免算法和慢啓動算法是兩個目的不一樣、獨立的算法。慢啓動的目的是:防止一開始速率過快,致使耗盡中間路由器存儲空間,從而嚴重下降TCP鏈接的吞吐量。擁塞避免的目的是:當擁塞發生時,下降網絡的傳輸速率。這能夠經過調用慢啓動的動做來下降網絡的傳輸速率。因此在實際中這兩個算法一般在一塊兒實現。tcp
下述代碼描述的是慢啓動的過程(4.4BSD-Lite2)。
其將win置爲現有窗口的大小,同時慢啓動門限tp->snd_ssthresh設置爲現有窗口大小的一半。snd_cwnd(擁塞窗口)被設定爲只能容納一個報文t_maxseg),這樣就強迫TCP執行慢啓動。以後擁塞窗口會先以指數形式增加,達到慢啓動門限snd_ssthressh以後,再線性增加。分佈式
線性增加的過程便是擁塞避免算法。
此過程如如下代碼註釋所示(4.4BSD-Lite2):
慢啓動圖例:
圖中Cwnd指數增加的階段,即從1到ssthresh時間段是過程是慢啓動。
圖中Cwnd線性增加的階段,即從ssthresh到max的時間段是擁塞避免的過程。
值得注意的是,TCP鏈接剛創建時刻也會有慢啓動的過程。若是用的是短鏈接(即發送一個請求以後即拋棄此鏈接)且發送數據較少的話,大部分時間都耗在了慢啓動上面,並無充分的利用帶寬。再加上創建鏈接所須要三次握手的消耗,致使短鏈接的效率要遠低於長鏈接。
通過上述討論,可知TCP窗口的大小取決於當前的網絡情況、對端的緩衝大小等等因素,TCP將這些都從底層屏蔽。開發者沒法從應用層獲取這些信息。這就意味着,當你在接收TCP數據流的時候沒法知道當前接收了有多少數據流,數據可能在任意一個比特位(seq)上。這就是所謂的"粘包"問題。開發者必須當心的組織幀格式來解決"粘包"。
精心整理 | 2017下半年文章目錄
分佈式之消息隊列複習精講(下)
面試之鏈表問題集錦(下)
數學分析告訴咱們什麼?
C++中的類型轉換
Stack Overflow 10個關於程序員有趣的調查
碼農有道,爲您提供通俗易懂的技術文章,讓技術變的更簡單!