剛開始嘗試使用java等後端語言寫IO流,或用套接字(socket)實現簡單C/S通訊的同窗們,經常會接觸到的一個概念:就是所謂的「三次握手」,socket做爲一個API接口,封裝了TCP/IP通訊的細節,使咱們只須要調用簡單的接口而無需關心具體的實現,那麼java
三次握手的過程實際上就是相互拋/接(3次)包的過程算法
創建鏈接後客戶端即可從服務器接收數據包進行通訊後端
注意:三次握手時拋/接的包和鏈接創建後收發的數據包是不一樣的!前者是隻攜帶有TCP報文和IP報文頭部的包,不攜帶具體的數據內容,而後者除了TCP和IP報文頭部還攜帶了具體的數據服務器
l 發送端 --> 數據包 --> 接收端網絡
l 接收端 --> ACK確認應答 --> 發送端socket
這裏的發送端/接收端能夠是客戶端/服務器,也能夠是服務器/客戶端,由於TCP通訊是全雙工通訊,因此創建鏈接後能夠同時進行如下兩個過程:性能
A. 客戶端 --> 數據包 --> 服務器 --> ACK應答 --> 客戶端spa
B. 服務器 --> 數據包 --> 客戶端 --> ACK應答 --> 服務器3d
以下圖三次握手時交換包的具體組成:TCP首部+IP首部(無具體數據內容!)blog
TCP通訊以段爲單位,段由TCP數據和TCP首部組成
若是再將網絡層的IP協議考慮進去的話,TCP/IP通訊以IP分組爲單位
IP分組=TCP段+IP首部=(TCP數據+TCP首部)+IP首部
注:TCP首部也算是IP數據包的一部分
創建鏈接後,最簡單的TCP通行是串行進行的,單次通訊發送端只能發送一個段。只有在接收到接收端發來的ACK應答包前,才能將第二個段發出去,這段時間內發送端只能空等待
很顯然,串行通訊效率很低,因此咱們想,能不能在第一個段發送出去後,無需等待ACK應答的返回就發送第二個段呢?這樣效率不就提升了嗎?基於這個理念人們提出了窗口的概念:
窗口:無需等待ACK應答的返回就能夠連續發送的段的數量的最大值
上圖中,窗口大小爲4,段的發送就好像管道通常,窗口大小就比如是「管道」的流量
HTTP做爲一種應用層協議,其事務處理要依賴於傳輸層的TCP協議機制的運做,因此HTTP事務處理的性能瓶頸很大程度上來源於TCP鏈接,體如今下面幾點:
解決方法:採用HTTP持久鏈接技術消除屢次鏈接的時延
TCP慢啓動機制體如今兩方面:
a.限制初次啓動時發送的段的數量:
上面提到了TCP窗口的概念,但TCP能不能一開始就發送窗口上限的段呢?答案是不能的,由於這會形成網絡擁塞,爲了不這個問題,TCP採用了慢啓動機制,一開始發送的段數爲1,拋接完成後將段數上升爲2,而後是4,再而後是8,段數將以指數形式遞增,直到窗口大小的上限
b.設置慢啓動閥值
由上圖能夠看到,當達到擁堵窗口的大小時,將致使超時重發,這時初次發送的段數又從1開始指數遞增,不一樣的地方是:這時候設置了慢啓動閥值(擁堵窗口的一半),發送的段數達到慢啓動閥值時,將再也不以指數形式上升,而是按必定的比例緩慢得直線上升
解決方法:正是由於單次TCP鏈接的時延和TCP的慢啓動機制,HTTP的持久鏈接才顯得尤其重要
TCP協議自己並無有規定發送單個段的數據包大小的最小值,那讓咱們想一想,若是咱們試圖在單個段中發送幾個字節的數據包會怎樣呢?若是這樣,TCP將經過Nagle算法的機制來提升網絡利用率,很顯然,將包含數據量極小的段都單獨發出去將會極大下降網絡利用率,因此經過Nagle算法,不直接派發小數據量的段,而是選擇將它們綁定在一塊兒,當達到要求尺寸後纔派發出去,這形成了時間上的延遲。Nagle算法是一把雙刃劍,它提升了網絡利用率,但同時形成了TCP的時延
解決方法:Nagle是能夠選擇關閉的,固然,前提是你得在TCP通訊中寫入大塊的數據
《HTTP權威指南》做者古爾利
《圖解TCP/IP》做者竹下隆史