Socket 核心原理分享

Socket 的個人故事。希望通過這篇文章讓你弄懂什麼是 Socket,明白 TCP 和 UDP 協議的通訊,明白長連接和短連接的優缺點,明白 BIO、NIO、AIO的區別。

Socket

大家好,我是 Socket。很多人都知道我,但是都不清楚我。給你看一下我和大佬的合影。

我很榮幸能與 TCP/IP 五層模型中的各位大佬站在一起,但我並不屬於他們中的任何一層。我的存在只是為了讓應用層的使用者能更簡單地將數據丟給傳輸層。他們不需要關係 TCP/IP 協議族的複雜內容。有什麼問題直接找我,我來幫你搞定。SO,你們可以把我理解成是應用層與TCP/IP協議族通信的抽象層、函數庫。

物理層:規範傳輸介質的規格特性(接口大小、形狀、引線數量、電壓範圍等),讓比特流能在各種傳輸媒體之間傳輸。
鏈路層:提供介質訪問和鏈路管理,主要將源計算機網絡層來的數據可靠的傳輸到相鄰節點的目標計算機的網絡層。
網絡層:提供了主機到主機的通信服務和各種形式的進程到進程的通信。實現兩個端系統之間的數據透明傳送,使傳輸層不需要了解網絡中的數據傳輸和交換技術。
傳輸層:主要負責向兩個主機中進程之間的通信提供服務。
應用層:為應用程序提供服務。

TCP 和 UDP

前面介紹過,我是應用層和傳輸層之間的抽象層。他們之間的通訊都是通過我來完成,可以把我理解成網絡通信的基本操作單元。有時候通訊多了,可真把我給類壞了。比如很多時候應用層會有多個程序往傳輸層進行通信。這時候會有多個 TCP (UDP)連接,或者多個應用進程用同一個 TCP (UDP)連接。為了避免各個連接通訊混亂的問題,我可費了不少心思。
我有三寶:協議、IP地址、端口
協議:一種約定和規範。只有通訊雙方使用同一種協議才能互相通訊。
地址:目標主機的地址。不管是客戶端還是服務端,都需要一個IP地址。
端口:用於區分網絡程序的唯一標識。目標主機上會有很多的網絡應用,他們各佔一個端口,互不衝突。

TCP

TCP 傳輸控制協議(Transmission Control Protocol)是一種面向連接、可靠、基於位元組流的傳輸層通信協議。在建立連接時需要進行三次握手,已確保在不穩定的網絡環境下能進行可靠的傳輸。在斷開連接時需要進行四次揮手,已確保雙方通訊的數據完整。

三次握手
第一次握手:從客服端發往服務端,發 syn 包,看能否連上服務器。需要等待服務器確認。
第二次握手:從服務端發往客戶端,發 ack 包,通知客戶端你能連上我。同時發送 syn 包,看能否連上客戶端。需要等待客戶端確認。
第三次握手:從客服端發往服務端,發 ack 包,通知服務端你能連上我。

四次揮手
第一次揮手:從客戶端發往服務端,發 fin 包,告知服務端要斷開連接。
第二次揮手:從服務端發往客戶端,發 ack 包,通知客戶端你的請求我收到了,但是我還沒有準備好,等通知。
第三次揮手:從服務端發往客戶端,發 fin 包,告知客戶端我已經要斷開連接了。
第四次握手:從客戶端發往服務端,發 ack 包,通知服務端你的請求我收到了,如果你不回我消息,我也斷開連接了。

TCP Socket 通訊流程圖如下。

首先服務端需要調用 socket 函數,生成一個用於通信的套接字文件描述符 sockfd。
隨後服務端需要調用 bind 函數,將服務器 IP 和 PORT 綁定到這個 sockfd 上。
然後服務器開始調用 listen 函數,套接字從 CLOSE 轉變為 LISTEN,成為對外提供 TCP 連接的窗口。監聽客戶端的請求。
監聽到客戶端請求後開始調用 accept 函數,接收請求的參數,包括客戶端創來的 IP 和 PORT。若接收成功則會創建一個新的 sockfd 與客戶端進行 IO 操作。
最後通訊結束後調用 close 函數,與客戶端進行四次揮手後關閉,釋放資源。
客戶端發起連接時調用 connect 函數,帶上自身的 IP、隨機的 PORT 和 sockfd 向目標服務器開始三次握手建立連接。

UDP

UDP 用戶數據報協議(User Datagram Protocol)是無連接的,面向消息的,提供高效率服務。UDP 不需要連接,少了三次握手和四次揮手的操作,從而對資源的佔用率更少、處理的網絡請求和響應效率更快。但他不能保障在極端的情況下載通訊不會丟失。

UDP 在綁定目標主機地址後,便可以通過 Sendto 和 Recvfrom 發送和接受數據。

長連接和短連接

長連接:通訊雙方在有數據交互時建立一個 TCP 連接,並一直保持連接狀態。
短連接:通訊雙方在有數據交互時就建立一個 TCP 連接,數據交互完成後斷開連接。

長連接不需要頻發建立連接,適用於頻繁請求的客戶。減少了短連接頻繁創建連接帶來的資源開銷。但是長連接如果過多也會多服務器帶來很大的壓力。長連接的應用場景相比短連接要少點。使用建議定時發送心跳包,以維持連接的狀態。且長連接的數量不宜過多。

短連接對於服務器而言比較簡單,每個連接都是有用的,不需要像長連接一樣需要額外維護。

BIO NIO AIO

BIO 全稱Block-IO 是一種阻塞同步的通信模式。我們常說的Stock IO 一般指的是BIO。是一個比較傳統的通信方式,模式簡單,使用方便。但並發處理能力低,通信耗時,依賴網速。
NIO 全稱New IO,也叫Non-Block IO 是一種非阻塞同步的通信模式。
AIO 也叫NIO2.0 是一種非阻塞異步的通信模式。在NIO的基礎上引入了新的異步通道的概念,並提供了異步文件通道和異步套接字通道的實現。

BIO 設計原理:
服務器通過一個Acceptor線程負責監聽客戶端請求和為每個客戶端創建一個新的線程進行鏈路處理。典型的一請求一應答模式。若客戶端數量增多,頻繁地創建和銷毀線程會給服務器打開很大的壓力。後改良為用線程池的方式代替新增線程,被稱為偽異步IO。
服務器提供IP地址和監聽的端口,客戶端通過TCP的三次握手與服務器連接,連接成功後,雙放才能通過套接字(Stock)通信。

NIO 設計原理:
NIO 相對於BIO來說一大進步。客戶端和服務器之間通過Channel通信。NIO可以在Channel進行讀寫操作。這些Channel都會被註冊在Selector多路復用器上。Selector通過一個線程不停的輪詢這些Channel。找出已經準備就緒的Channel執行IO操作。
NIO 通過一個線程輪詢,實現千萬個客戶端的請求,這就是非阻塞NIO的特點。

AIO 設計原理:
AIO 並沒有採用NIO的多路復用器,而是使用異步通道的概念。其read,write方法的返回類型都是Future對象。而Future模型是異步的,其核心思想是:去主函數等待時間。

BIO NIO AIO 的詳細知識可以參考我的另外一篇文章 :Netty序章之BIO NIO AIO演變