1. 程式人生 > >分散式架構基礎-TCP/IP 通訊協議

分散式架構基礎-TCP/IP 通訊協議

一個http請求,在整個網路中的請求過程

當應用程式用TCP傳送資料時,資料被送入協議棧中,然後逐個通過每一層直到被當作一串位元流送入網路,其中每一層對收到的資料都要增加一些首部資訊。
這裡寫圖片描述
當目的主機收到一個乙太網資料幀時,資料就開始從協議棧中由底向上升,同時去掉各層協議加上的報文首部。每層協議盒都要去檢查報文首部中的協議標識,以確定接收資料的上層協議,這個過程稱作分用。
這裡寫圖片描述
為什麼有了MAC層還要走IP層呢?
mac地址就好像個人的身份證號,人的身份證號和人戶口所在的城市,出生的日期有關,但是和人所在的位置沒有關係,人是會移動的,知道一個人的身份證號,並不能找到它這個人。mac地址類似,它是和裝置的生產者,批次,日期之類的關聯起來,知道一個裝置的mac,並不能在網路中將資料傳送給它,除非它和傳送方的在同一個網路內。所以要實現機器之間的通訊,還需要有 ip 地址的概念,ip地址表達的是當前機器在網路中的位置,類似於城市名+道路號+門牌號的概念。通過ip層的定址,我們能知道按何種路徑在全世界任意兩臺Internet上的機器間傳輸資料。

IP協議和TCP/UDP協議

什麼是協議?
協議,就是兩個需要通過網路通訊的程式達成的一種約定,它規定了報文的交換方式和包含的意義。比如(HTTP)為了解決在伺服器之間傳遞超文字物件的問題,這些超文字物件在伺服器中建立和儲存,並由Web瀏覽器進行視覺化,完成使用者對遠端內容的感知和體驗。
什麼是IP協議?
TCP和UDP是兩種最為著名的傳輸層協議,他們都是使用IP作為網路層協議。IP協議提供了一組資料報文服務,每組分組報文都是由網路獨立處理和分發,就像寄送快遞包裹一樣,為了實現這個功能,每個IP報文必須包含一個目的地址的欄位,就像我們寄送快遞都需要寫明收件人資訊,但是和我們寄送快遞一樣,也可能會出現包裹丟失問題,所以IP協議只是一個“盡力而為”的協議,在網路傳輸過程中,可能會發生報文丟失、報文順序打亂,重複傳送的情況。IP協議層之上的傳輸層,提供了兩種可以選擇的協議,TCP、UPD。這兩種協議都是建立在IP層所提供的服務基礎上,根據應用程式的不同需求選擇不同方式的傳輸。
TCP/IP


TCP協議能夠檢測和恢復IP層提供的主機到主機的通訊中可能發生的報文丟失、重複及其他錯誤。TCP提供了一個可信賴的位元組流通道,這樣應用程式就不需要考慮這些問題。同時,TCP協議是一種面向連線的協議,在使用TCP進行通訊之前,兩個應用程式之間需要建立一個TCP連線,而這個連線又涉及到兩臺電腦需要完成握手訊息的交換。
UDP/IP
UDP協議不會對IP層產生的錯誤進行修復,而是簡單的擴充套件了IP協議“盡力而為”的資料報文服務,使他能夠在應用程式之間工作,而不是在主機之間工作,因此使用UDP協議必須要考慮到報文丟失,順序混亂的問題。
TCP 是如何做到可靠傳輸的?
TCP三次握手的過程

由於TCP協議是一種可信的傳輸協議,所以在傳輸之前,需要通過三次握手建立一個連線,所謂的三次握手,就是在建立TCP連線時,需要客戶端和服務端總共傳送 3個包來確認連線的建立。
這裡寫圖片描述
ACK: TCP協議規定,只有ACK=1時有效,也規定連線建立後所有傳送的報文的ACK必須為1
SYN(SYNchronization) : 在連線建立時用來同步序號。當SYN=1而ACK=0時,表明這是一個連線請求報文。對方若同意建立連線,則應在響應報文中使SYN=1和ACK=1。因此,SYN置1就表示這是一個連線請求或連線接受報文。
FIN(finis)即完,終結的意思, 用來釋放一個連線。當FIN = 1時,表明此報文段的傳送方的資料已經發送完畢,並要求釋放連線。
TCP四次揮手的過程
四次揮手錶示TCP斷開連線的時候,需要客戶端和服務端總共傳送4個包以確認連線的斷開。客戶端或伺服器均可主動發起揮手動作(因為TCP是一個全雙工協議),在socket程式設計中,任何一方執行close()操作即可產生揮手操作。
這裡寫圖片描述
為什麼連線的時候是三次握手,關閉的時候卻是四次握手?
三次握手是因為當Server端收到Client端的SYN連線請求報文後,可以直接傳送 SYN+ACK報文。其中ACK報文是用來應答的,SYN報文是用來同步的。但是關閉連線時,當Server端收到FIN報文時,很可能並不會立即關閉SOCKET(因為可能還有訊息沒處理完),所以只能先回復一個ACK報文,告訴Client端,”你發的FIN報文我收到了”。只有等到我Serve 端所有的報文都發送完了,我才能傳送FIN報文,因此不能一起傳送,故需要四步握手。
資料傳輸過程的流量控制和確認機制
建立可靠連線以後,就開始進行資料傳輸了。在通訊過程中,最重要的是資料包,也就是協議傳輸的資料。如果資料的傳送與接收過程當中出現收方來不及接收的情況,這時就需要對發方進行控制以免資料丟失。利用滑動視窗機制可以很方便的在 TCP連線上實現對傳送方的流量控制。TCP的視窗單位是位元組,不是報文段,傳送方的傳送視窗不能超過接收方給出的接收視窗的數值。
滑動視窗協議
線上滑動視窗演示動畫
滑動視窗(Sliding window)是一種流量控制技術。早期的網路通訊中,通訊雙方不會考慮網路的擁擠情況直接傳送資料。由於大家不知道網路擁塞狀況,同時傳送資料,導致中間節點阻塞掉包,誰也發不了資料,所以就有了滑動視窗機制來解決此問題。傳送和接受方都會維護一個數據幀的序列,這個序列被稱作視窗。
這裡寫圖片描述
以上圖解
傳送方和接收方都會維護一個數據幀的序列,這個序列被稱作視窗。傳送方的視窗大小由接收方確定,目的在於控制傳送速度,以免接收方的快取不夠大而導致溢位,同時控制流量也可以避免網路擁塞。上圖中的4,5,6 號資料幀已經被髮送出去,但是未收到關聯的ACK,7,8,9 幀則是等待發送。可以看出傳送端的視窗大小為6,這是由接收方告知的。此時如果傳送端收到4號ACK,則視窗的左邊緣向右收縮,視窗的右邊緣則向右擴充套件,此時視窗就向前“滑動了”,即資料幀10也可以等待被髮送。
傳送視窗
就是傳送端允許連續傳送的幀的序號表。傳送端可以不等待應答而連續傳送的最大幀數稱為傳送視窗的尺寸。
接收視窗
接收方允許接收的幀的序號表,凡落在接收視窗內的幀,接收方都必須處理,落在接收視窗外的幀被丟棄。接收方每次允許接收的幀數稱為接收視窗的尺寸。

TCP通訊的效能問題

正常的通訊過程如下(BIO):
這裡寫圖片描述
我們發現TCP響應伺服器一次只能處理一個客戶端請求,當一個客戶端向一個已經被其他客戶端佔用的伺服器傳送連線請求時,雖然在連線建立後可以向服務端傳送資料,但是在服務端處理完之前的請求之前,卻不會對新的客戶端做出響應,這種型別的伺服器稱為“迭代伺服器”。迭代伺服器是按照順序處理客戶端請求,也就是服務端必須要處理完前一個請求才能對下一個客戶端的請求進行響應。但是在實際應用中,我們不能接受這樣的處理方式。所以我們需要一種方法可以獨立處理每一個連線,並且他們之間不會相互干擾。而Java提供的多執行緒技術剛好滿足這個需求,這個機制使得伺服器能夠方便處理多個客戶端的請求。
TCP協議的通訊過程
對於TCP通訊來說,每個TCP Socket的核心中都有一個傳送緩衝區和一個接收緩衝區,TCP的全雙工的工作模式及TCP的滑動視窗就是依賴於這兩個獨立的Buffer和該Buffer的填充狀態。
接收緩衝區把資料快取到核心,若應用程序一直沒有呼叫Socket的read方法進行讀取,那麼該資料會一直被快取在接收緩衝區內。不管程序是否讀取Socket,對端發來的資料都會經過核心接收並快取到Socket的核心接收緩衝區。
read所要做的工作,就是把核心接收緩衝區中的資料複製到應用層使用者的Buffer裡。程序呼叫Socket的send傳送資料的時候,一般情況下是將資料從應用層使用者的Buffer裡複製到Socket的核心傳送緩衝區,然後send就會在上層返回。換句話說,send返回時,資料不一定會被髮送到對端。
這裡寫圖片描述
Socket的接收緩衝區被TCP用來快取網路上收到的資料,一直儲存到應用程序讀走為止。如果應用程序一直沒有讀取,那麼Buffer滿了以後,出現的情況是:通知對端TCP協議中的視窗關閉,保證TCP接收緩衝區不會移除,保證了TCP是可靠傳輸的。如果對方無視視窗大小發出了超過視窗大小的資料,那麼接收方會把這些資料丟棄。
如何使用非阻塞提高效能?
非阻塞要解決的就是I/O執行緒與Socket解耦的問題,因此,它引入了事件機制來達到解耦的目的。我們可以認為NIO底層中存在一個I/O排程執行緒,它不斷的掃描每個Socket的緩衝區,當發現寫入緩衝區為空的時候,它會產生一個Socket可寫事件,此時程式就可以把資料寫入到Socket中。如果一次寫不完,就等待下一次的可寫事件通知。反之,當發現緩衝區裡有資料的時候,它會產生一個Socket可讀事件,程式收到這個通知事件就可以從Socket讀取資料了。
關於NIO
實際上基於上面講的傳統的BIO模型,一個請求一個執行緒的方式,如果要涉及到上千個客戶端訪問時,會產生很多的問題,比如擴充套件性、系統資源開銷等等。所以我們需要一種方法來輪詢一組客戶端,來查詢哪個連線需要提供服務,這個就是我們講的“NIO”。
緩衝區
在NIO中,所有資料都是用緩衝區處理,在讀取資料的時候,它是直接讀到緩衝區中,在寫入資料的時候,也是寫到緩衝區。任何時候訪問NIO中的資料,都是通過緩衝區進行的操作。
通道
Channel通道,就像一個自來水管一樣,可以通過它讀取和寫入資料,Channel是全雙工的,所以資料是雙向流動。
多路複用
多路複用器Selector,是NIO的基礎,多路複用器提供選擇已經就緒的任務的能力,簡單來說,Selector會不斷輪詢註冊上的Channel,如果某個Channel上面有新的TCP連線接入、讀、寫事件,這個Channel就處於就緒狀態,會被Selector輪詢出來,然後通過 SelectionKey可以獲取就緒的Channel進行I/O操作。一個多路複用器可以同時輪詢多個 Channel,通過這個機制可以接入成千上萬的客戶端。
這裡寫圖片描述