運輸層
網絡層爲主機間提供通訊,運輸層爲應用程序提供通信。網絡層IP數據報僅僅能實現兩個主機點對點間的通訊,而傳輸層實現的是兩個主機進程間的通訊(應用程序互相通訊)。緩存
TCP協議
概述
TCP協議和UDP協議處於同一層:傳輸層,可是二者之間有很大的區別,TCP協議具備如下特色:服務器
- TCP提供可靠的數據傳輸服務,TCP是面向鏈接的,即數據在通訊之間要先創建鏈接,結束通訊時要釋放鏈接,這也是後面所說的3次握手,4次揮手;
- TCP是點對點的鏈接方式,即一條TCP鏈接兩端只能是兩個端點;
- TCP提供可靠的,無差錯的,不丟失,不重複,按順序的服務;
- TCP提供全雙工通訊,容許通訊雙方任什麼時候候都能發送數據,TCP在鏈接的兩端都設置有發送緩存和接收緩存;
- TCP是面向字節流的,TCP傳輸的數據是一個一個字節的按序傳輸的,數據塊與數據塊之間沒有邊界信息,對於TCP來講,全部數據都是同樣的,TCP不能區分數據的意義。
TCP報文結構:
TCP 報文段的報頭有前 20 字節的固定部分,後面 4n 字節是根據須要而添加的字段,下圖是TCP完整的報文結構:網絡
20 字節的固定部分,各字段功能說明:併發
- 源端口和目的端口: 各佔 2 個字節,分別寫入源端口號和目的端口號。這和 UDP 報頭有相似之處,由於都是運輸層協議。
- 序號: 佔 4 字節序,序號範圍[0,2^32-1],序號增長到 2^32-1 後,下個序號又回到 0。 TCP 是面向字節流的,經過 TCP 傳送的字節流中的每一個字節都按順序編號,而報頭中的序號字段值則指的是本報文段數據的第一個字節的序號。
- 確認序號: 佔 4 字節,指望收到對方下個報文段的第一個數據字節的序號。
- 數據偏移: 佔 4 位,指 TCP 報文段的報頭長度,包括固定的 20 字節和選項字段。
- 保留: 佔 6 位,保留爲從此使用,目前爲 0。
- 控制位: 共有 6 個控制位,說明本報文的性質,意義以下:
URG 緊急:當 URG=1 時,它告訴系統此報文中有緊急數據,應優先傳送(好比緊急關閉),這要與緊急指針字段配合使用。
ACK 確認:僅當 ACK=1 時確認號字段纔有效。創建 TCP 鏈接後,全部報文段都必須把 ACK 字段置爲 1。
PSH 推送:若 TCP 鏈接的一端但願另外一端當即響應,PSH 字段即可以「催促」對方,再也不等到緩存區填滿才發送。
RET 復位:若 TCP 鏈接出現嚴重差錯,RST 置爲 1,斷開 TCP 鏈接,再從新創建鏈接。
SYN 同步:用於創建和釋放鏈接,稍後會詳細介紹。
FIN 終止:用於釋放鏈接,當 FIN=1,代表發送方已經發送完畢,要求釋放 TCP 鏈接。
- 窗口: 佔 2 個字節。窗口值是指發送者本身的接收窗口大小,由於接收緩存的空間有限。
- 檢驗和: 2 個字節。和 UDP 報文同樣,有一個檢驗和,用於檢查報文是否在傳輸過程當中出差錯。
- 緊急指針: 2 字節。當 URG=1 時纔有效,指出本報文段緊急數據的字節數。
- 選項: 長度可變,最長可達 40 字節。具體的選項字段,須要時再作介紹。
TCP鏈接和釋放:
3.1. 三次握手
TCP三次握手過程:socket
- 客戶端發出請求鏈接報文段,其中報頭控制位 SYN=1,初始序號 seq=x。客戶端進入 SYN-SENT(同步已發送)狀態。
- 服務端收到請求報文段後,向客戶端發送確認報文段。確認報文段的首部中 SYN=1,ACK=1,確認號是 ack=x+1,同時爲本身選擇一個初始序號 seq=y。服務端進入 SYN-RCVD(同步收到)狀態。
- 客戶端收到服務端的確認報文段後,還要給服務端發送一個確認報文段。這個報文段中 ACK=1,確認號 ack=y+1,而本身的序號 seq=x+1。這個報文段已經能夠攜帶數據,若是不攜帶數據則不消耗序號,則下一個報文段序號仍爲 seq=x+1。
- 至此 TCP 鏈接已經創建,客戶端進入 ESTABLISHED(已創建鏈接)狀態,當服務端收到確認後,也進入 ESTABLISHED 狀態,它們之間即可以正式傳輸數據了。
3.2. 四次揮手
TCP四次揮手過程:spa
注意此時鏈接尚未釋放,須要時間等待狀態結束後(4 分鐘) 鏈接兩端纔會 CLOSED。設置時間等待是由於,有可能最後一個確認報文丟失而須要重傳,下面具體闡述TIME-WAIT(時間等待)狀態的緣由:設計
TIME_WAIT狀態維持的時間是最長分節生命期的2倍,2MSL(MSL=30s~120s)指針
3.3. TIME-WAIT狀態的帶來的影響和解決方法
因爲TIME-WAIT狀態的存在,使得socket能夠進入和留存至關長一段時間,若是你的系統中有不少 socket 處於TIME-WAIT狀態,那麼當你須要建立新的 socket 鏈接的時候可能會受到影響,這也會影響到你的程序的擴展性。由於在一個TCP鏈接中,一個Socket若是關閉的話,它將保持TIME-WAIT狀態大約 4分鐘 。若是不少鏈接快速的打開和關閉的話,系統中處於TIME-WAIT狀態的socket將會積累不少,你可使用netstat命令查看處於TIME-WAIT狀態的socket。因爲本地端口數量的限制,同一時間只有有限數量的socket鏈接能夠創建,若是太多的socket處於TIME_WAIT狀態,你會發現,因爲用於新建鏈接的本地端口太缺少,將會很難再創建新的對外鏈接。在Linux中,能夠經過設置SO_REUSEADDR容許鏈接重用,TIME-WAIT的存在是有它的理由的,經過縮短2MSL的時間或者使用SO-REUSEADDR容許鏈接重用並不老是好主意。若是你有能力去設計你的協議避免TIME-WAIT產生的問題的話,你就能夠避免這裏全部的問題。視頻
- 此時 TCP 鏈接兩端都還處於 ESTABLISHED 狀態,客戶端中止發送數據,併發出一個 FIN 報文段。首部 FIN=1,序號 seq=u(u 等於客戶端傳輸數據最後一字節的序號加 1)。客戶端進入 FIN-WAIT-1(終止等待 1)狀態。
- 服務端回覆確認報文段,確認號 ack=u+1,序號 seq=v(v 等於服務端傳輸數據最後一字節的序號加 1),服務端進入 CLOSE-WAIT(關閉等待)狀態。如今 TCP 鏈接處於半開半閉狀態,服務端若是繼續發送數據,客戶端依然接收。
- 客戶端收到確認報文,進入 FIN-WAIT-2 狀態,服務端處理完數據後,發出 FIN 報文段,FIN=1,確認號 ack=u+1,而後進入 LAST-ACK(最後確認)狀態。
- 客戶端回覆確認確認報文段,ACK=1,確認號 ack=w+1(w 爲半開半閉狀態時,收到的最後一個字節數據的編號) ,序號 seq=u+1,而後進入 TIME-WAIT(時間等待)狀態。
- 緣由一:可靠的實現TCP全雙工鏈接的終止
若是客戶端在接收到服務器端的FIN後,發送的ACK分組在通路中丟失,因爲超時重傳機制,服務器端沒有接受到來自客戶端的應答,所以從新發送FIN,這時總共經歷的時間最大可能爲2MSL,當第二個FIN到達時,保證在客戶端維護必要的狀態信息,確保可以發送最終的ACK,保證兩邊都可以關閉。
- 緣由二:容許老的重複分節在網絡中消逝
若是關閉一個連接後,立刻創建新的連接,這個連接的IP地址和端口號和剛關閉的連接相同,這時候若是上一個連接中重複的分節沒有消逝,這時這個重複的分節就有可能被新的連接接收,因此爲了防止舊連接中的分節可以消逝,不影響新連接,將TIME_WAIT設置爲2倍的MSL。
-
TCP可靠傳輸的實現:排序
超時重傳機制很費時間,每發送一個數據報都要等待確認。在實際應用中的確不是這樣的,真實狀況是,採用了流水線傳輸:發送方能夠連續發送多個報文段(連續發送的數據長度叫作窗口),而沒必要每發完一段就停下來等待確認。實際應用中,接收方也沒必要對收到的每一個報文都作回覆,而是採用累積確認方式:接收者收到多個連續的報文段後,只回復確認最後一個報文段,表示在這以前的數據都已收到。這樣,傳輸效率獲得了很大的提高。
- (1) TCP 報文段的長度可變,根據收發雙方的緩存狀態、網絡狀態而調整。
- (2) 當 TCP 收到發自 TCP 鏈接另外一端的數據,它將發送一個確認。
- (3) 當 TCP 發出一個段後,它啓動一個定時器,等待目的端確認收到這個報文段,若是不能及時收到一個確認,將重發這個報文段。這就是稍後介紹的超時重傳。
- (4) TCP 將保持它首部和數據的檢驗和。若是經過檢驗和發現報文段有差錯,這個報文段將被丟棄,等待超時重傳。
- (5) TCP 將數據按字節排序,報文段中有序號,以確保順序的正確性。
- (6) TCP 還能提供流量控制。TCP 鏈接的每一方都有收發緩存。TCP 的接收端只容許另外一端發送接收端緩衝區所能接納的數據。這將防止較快主機導致較慢主機的緩衝區溢出。
UDP協議
用戶數據報協議,它只在 IP 數據報服務之上增長了不多一點功能,它的主要特色有:
(1) UDP 是無鏈接的,發送數據以前不須要創建鏈接(而 TCP 須要),減小了開銷和時延。
(2) UDP盡最大努力交付,不保證交付可靠性。
(3) UDP 是面向報文的,對於從網絡層交付下來的 IP 數據報,只作很簡單的封裝(8 字節 UDP 報頭),首部開銷小。
(4) UDP 沒有擁塞控制,出現網絡擁塞時發送方也不會下降發送速率。這種特性對某些實時應用是很重要的,好比 IP 電話,視頻會議等,它們容許擁塞時丟失一些數據,由於若是不拋棄這些數據,很可能形成時延的累積。
(5) UDP 支持一對1、一對多、多對一和多對多的交互通訊。
UDP報文:
UDP 數據報可分爲兩部分:UDP 報頭和數據部分。其中數據部分是應用層交付下來的數據。UDP 報頭總共 8 字節,而這 8 字節又分爲 4 個字段:
(1)源端口 2 字節 在對方須要回信時可用,不須要時能夠全 0;
(2)目的端口 2 字節 必須,也是最重要的字段;
(3)長度 2 字節 長度值包括報頭和數據部分;
(4)校驗和 2 字節 用於檢驗 UDP 數據報在傳輸過程當中是否有出錯,有錯就丟棄。
面向報文的傳輸方式是應用層交給UDP多長的報文,UDP就照樣發送,即一次發送一個報文。所以,應用程序必須選擇合適大小的報文。若報文太長,則IP層須要分片,下降效率。若過短,會是IP過小。UDP對應用層交下來的報文,既不合並,也不拆分,而是保留這些報文的邊界。這也就是說,應用層交給UDP多長的報文,UDP就照樣發送,即一次發送一個報文。
面向字節流的話,雖然應用程序和TCP的交互是一次一個數據塊(大小不等),但TCP把應用程序當作是一連串的無結構的字節流。TCP有一個緩衝,當應用程序傳送的數據塊太長,TCP就能夠把它劃分短一些再傳送。若是應用程序一次只發送一個字節,TCP也能夠等待積累有足夠多的字節後再構成報文段發送出去。
TCP和UDP的對比: