分散式通訊協議-TCP/IP與常用IO方式
目錄
網路領域的知識
- 協議:tcp、udp、multicast
- IO(BIO、NIO、AIO)
- Socket
- NIO(Netty/Mina)
- 序列化和反序列化
TCP傳輸過程
http請求:
一個 http 請求,在整個網路中的請求過程當應用程式用TCP 傳送資料時,資料被送入協議棧中, 然後逐個通過每一層直到被當作一串位元流送入網路。其中每一層對收到的資料都要增加一些首部資訊
http響應:
當目的主機收到一個乙太網資料幀時,資料就開始從協議棧中由底向上升,同時去掉各層協議加上的報文首部。每層協議盒都要去檢查報文首部中的協議標識,以確定接收資料的上層協議。這個過程稱作分用
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 協議是一種可信的傳輸協議,所以在傳輸之前,需要通過三次握手建立一個連線,所謂的三次握手, 就是在建立 TCP 連結時,需要客戶端和服務端總共傳送 3 個包來確認連線的建立
TCP 四次揮手協議
四次揮手錶示 TCP 斷開連線的時候,需要客戶端和服務端總共傳送 4 個包以確認連線的斷開;客戶端或伺服器均可主動發起揮手動作(因為 TCP 是一個全雙工協議),在socket 程式設計中,任何一方執行 close() 操作即可產生揮手操作。
為什麼連線的時候是三次握手,關閉的時候卻是四次 握手?
三次握手是因為因為當Server 端收到Client 端的SYN 連線請求報文後,可以直接傳送SYN+ACK 報文。其中ACK報文是用來應答的,SYN 報文是用來同步的。但是關閉連線時,當Server 端收到FIN 報文時,很可能並不會立即關閉SOCKET(因為可能還有訊息沒處理完),所以只能先回復一個ACK 報文,告訴Client 端,"你發的FIN 報文我收到了"。只有等到我 Server 端所有的報文都發送完了,我才能傳送FIN 報文,因此不能一起傳送。故需要四步握手。
滑動視窗協議
資料傳輸過程的流量控制和確認機制
建立可靠連線以後,就開始進行資料傳輸了。在通訊過程中,最重要的是資料包,也就是協議傳輸的資料。如果資料的傳送與接收過程當中出現收方來不及接收的情況,這時就需要對發方進行控制以免資料丟失。利用滑動視窗機制可以很方便的在 TCP 連線上實現對傳送方的流量控制。TCP 的視窗單位是位元組,不是報文段,傳送方的傳送視窗不能超過接收方給出的接收視窗的數值。
傳送視窗
就是傳送端允許連續傳送的幀的序號表。
傳送端可以不等待應答而連續傳送的最大幀數稱為傳送視窗的尺寸。
接收視窗
接收方允許接收的幀的序號表,凡落在 接收視窗內的幀, 接收方都必須處理,落在接收視窗外的幀被丟棄。
接收方每次允許接收的幀數稱為接收視窗的尺寸。線上滑動視窗演示功能
https://media.pearsoncmg.com/aw/ecs_kurose_compnetwork_7/cw/content/interactiveanimations/selective-repeat- protocol/index.html
組播協議 Multicast
對於某些資訊,多個接受者都可能感興趣的時候,那麼我們應該怎麼解決呢?我們可以向每個接受者單播一個數據副本,但是如果這樣的話,效率會低;而且同樣的資料傳送多次,浪費頻寬。
解決方案是,我們可以把複製資料包的工作交給網路來做, 而不是由傳送者負責。這樣無論是多少客戶端,都沒問題有兩種分發型別,廣播(broadcast)和多播(multicast); 廣播:網路中的所有主機都會接收到一份資料副本
多播:訊息只發送給一個多播地址,網路只是將資料分發給哪些想要接收發送到該多播地址的資料的主機。總的來說,要實現這個功能,只有UDP 是最合適的
廣播
廣播是主機向子網內所有主機發送訊息,子網內所有主機都能收到來自某臺主機的廣播資訊,屬於點對所有點的通訊。廣播意味著網路向子網每一個主機都投遞一份資料包, 不論這些主機是否樂意接收該資料包;
多播
多播是主機向一組主機發送資訊,存在於某個組的所有主機都可以接收到訊息,屬於點對多點的通訊。
IO:BIO與NIO、AIO
IO的方式通常分為幾種,同步阻塞的BIO、同步非阻塞的NIO、非同步非阻塞的AIO。
事件分離器:在IO讀寫時,把 IO請求 與 讀寫操作 分離調配進行,需要用到事件分離器。根據處理機制的不同,事件分離器又分為:同步的Reactor和非同步的Proactor。
BIO與NIO一個比較重要的不同,是我們使用BIO的時候往往會引入多執行緒,每個連線一個單獨的執行緒;而NIO則是使用單執行緒或者只使用少量的多執行緒,每個連線共用一個執行緒。
AIO是發出IO請求後,由作業系統自己去獲取IO許可權並進行IO操作;NIO則是發出IO請求後,由執行緒不斷嘗試獲取IO許可權,獲取到後通知應用程式自己進行IO操作。
先來個例子理解一下概念,以銀行取款為例:
- 同步 : 自己親自出馬持銀行卡到銀行取錢(使用同步IO時,Java自己處理IO讀寫);
- 非同步 : 委託一小弟拿銀行卡到銀行取錢,然後給你(使用非同步IO時,Java將IO讀寫委託給OS處理,需要將資料緩衝區地址和大小傳給OS(銀行卡和密碼),OS需要支援非同步IO操作API);
- 阻塞 : ATM排隊取款,你只能等待(使用阻塞IO時,Java呼叫會一直阻塞到讀寫完成才返回);
- 非阻塞 : 櫃檯取款,取個號,然後坐在椅子上做其它事,等號廣播會通知你辦理,沒到號你就不能去,你可以不斷問大堂經理排到了沒有,大堂經理如果說還沒到你就不能去(使用非阻塞IO時,如果不能讀寫Java呼叫會馬上返回,當IO事件分發器會通知可讀寫時再繼續進行讀寫,不斷迴圈直到讀寫完成)
Java對BIO、NIO、AIO的支援:
-
Java BIO : 同步並阻塞,伺服器實現模式為一個連線一個執行緒,即客戶端有連線請求時伺服器端就需要啟動一個執行緒進行處理,如果這個連線不做任何事情會造成不必要的執行緒開銷,當然可以通過執行緒池機制改善。
-
Java NIO : 同步非阻塞,伺服器實現模式為一個請求一個執行緒,即客戶端傳送的連線請求都會註冊到多路複用器上,多路複用器輪詢到連線有I/O請求時才啟動一個執行緒進行處理。
-
Java AIO(NIO.2) : 非同步非阻塞,伺服器實現模式為一個有效請求一個執行緒,客戶端的I/O請求都是由OS先完成了再通知伺服器應用去啟動執行緒進行處理。
BIO、NIO、AIO適用場景分析:
-
BIO方式適用於連線數目比較小且固定的架構,這種方式對伺服器資源要求比較高,併發侷限於應用中,JDK1.4以前的唯一選擇,但程式直觀簡單易理解。
-
NIO方式適用於連線數目多且連線比較短(輕操作)的架構,比如聊天伺服器,併發侷限於應用中,程式設計比較複雜,JDK1.4開始支援。
-
AIO方式使用於連線數目多且連線比較長(重操作)的架構,比如相簿伺服器,充分呼叫OS參與併發操作,程式設計比較複雜,JDK7開始支援。