程式設計師修神之路--簡約而不簡單的分散式通訊基石

架構師修行之路發表於2020-07-21

分散式系統可以總結為是處於不同物理位置的多個程式組成的整體,為了確保這個整體有效並且高效的對外提供服務,每個節點之間都有可能需要進行通訊來交換資訊,而這個交換資訊的過程多數使用的是tcp協議。tcp協議是位於ip層之上的傳輸層協議,在這個傳輸層裡有兩個比較重要的協議:tcp和udp。對於應用層的開發人員來說,用的最多的就是這兩個協議,這也是一些面試官必問的知識點之一

無論是tcp還是udp,都是建立在ip+埠的規則之上,什麼意思呢?也就是說採用tcp和udp的程式都需要一個埠來讀取和寫入資料。

TCP協議

tcp協議是可靠的協議,而且是面向連線的,建立連線的過程會經過三次握手。為什麼會是三次握手而不是二次或者四次呢?

image

說到這個問題,可以抽象出一個場景,怎麼樣才能確定一端是和另外一端互通的呢?其實很簡單,一端傳送給另一端的訊息能順利給我答覆,這就說明兩端是聯通的。tcp協議的三次握手恰好說明了這一點,A和B通訊,只要三次握手,A能得到B的答覆,B也能得到A的答覆。

基於ip層傳送的報文,在網路中是無法確定是否正確到達對方的。tcp協議在ip協議之上新增了一系列資料結構和演算法來保證tcp的資料正確到達。

  1. tcp的資料包是有編號的,這麼做主要是為了解決順序問題,如果沒有編號,對方怎麼確定順序呢?另外一點,編號是為了傳送方來確認哪些包已經正確到達對方
  2. 當tcp的資料包被接收方接收,接收方需要傳送確認包給傳送方,傳送方在接收到確認包之後會把對應的資料包做狀態修改,由於每個資料包其實有超時機制,在超時之後,傳送方會進行重試
  3. tcp是面向位元組流的,傳送的時候發的是一個位元組流,這是tcp自己的狀態維護的事情。

說了這麼多,其實可以把tcp看做是一個有狀態的協議,它可以根據網路狀況,對方接收情況等諸多因素來調整自己的傳送狀態。

UPP協議

相對於tcp協議來說,udp要簡單很多

  1. udp協議不需要建立連線,這就意味著傳送方只要知道對方的ip和埠,就可以傳送,基於這一點可以做廣播。
    2.udp協議不負責可靠交付,因為它不像tcp協議那樣有一堆的演算法和資料結構來做保證。
  2. udp是基於資料包形式的,一個一個的發,一個一個的接收。而且udp資料的傳送不會根據因為網路環境的阻塞而改變

udp基於以上特性可以在網路環境比較好或者對於丟包不敏感的應用中使用。udp在捨棄了重傳,順序等一些列特性之後,處理速度特別快,在一些不敏感但是實時性要求比較高的場景中應用非常廣泛。

Socket

在有了tcp和udp協議之後,程式間通訊的基石就有了。但是總不能每次通訊自己都需要寫tcp的三次握手等這些複雜過程吧。為了遮蔽這些複雜的過程,使通訊程式簡單,在tcp和udp協議之上,便抽象出來了socket這個概念。

所謂套接字(Socket),就是對網路中不同主機上的應用程式之間進行雙向通訊的端點的抽象。一個套接字就是網路上程式通訊的一端,提供了應用層程式利用網路協議交換資料的機制。從所處的地位來講,套接字上聯應用程式,下聯網路協議棧,是應用程式通過網路協議進行通訊的介面,是應用程式與網路協議根進行互動的介面

socket是區分服務端和客戶端的,本地的socket與遠端的一個socket建立連線的過程,其實就是tcp協議三次握手的過程。一旦socket連線建立,就可以利用socket抽象出來的read或者write方法來進行通訊了。

socket需要指定使用的IP協議,還需要指定使用的是tcp還是udp協議。基於tcp協議的服務端的socket需要bind一個埠來listen並且accept客戶端的socket連線。這也是服務端socket和客戶端socket的一個區別。
image

對於udp來說,過程有點不一樣。udp是沒有連線的,一是不需要三次握手,二是不需要listen和connect,但是仍然需要ip和埠bind,要不然遠端的資料到來的時候,系統會找不到接收程式的。UDP是沒有連線狀態的,因而不需要每次連線都建立一組Socket,而是隻用一個Socket,就能夠和多個客戶端通訊。也正是因為沒有連線狀態,每次通訊的時候,呼叫sendto和recvfrom,都需要傳入 IP 地址和埠。

image

基於tcp的socket在核心中都有一個傳送緩衝區和接收緩衝區,tcp的雙工工作模式以及tcp的滑動視窗就是依賴於這兩個獨立的buffer以及buffer的資料填充狀態。接收緩衝區把資料快取入核心之中,如果對應的應用一直沒有呼叫socket的read方法進行資料讀取,則此資料會一直被快取在接收緩衝區中,如果接收緩衝區滿了,便會通知對方socket,以調整對方socket的傳送視窗大小,這就是滑動視窗的實現。如果對方仍然持續傳送資料,接收方在接收緩衝區沒有被讀取的情況下將丟棄後到的資料,這就是tcp的流量控制。對於udp來說,它沒有真正的傳送緩衝區,只要有資料就會傳送,無論對方能否正常正確接收,這也是udp丟包的原因之一,但是udp的socket 和tcp的socket一樣都會有接收緩衝區,而且行為也一樣。

寫在最後

有的面試官吹水,號稱http長連線,這個說法其實是不準確的,長連線和短連線是針對tcp協議而言,http只是建立在tcp/ip協議之上的應用層的一個協議。總體而言,tcp和udp設計的資料結構和演算法有很多,這裡只是粗略的說了一下,有興趣的同學可以去研究tcp協議那本書。

相關文章