經過面試的同學經常會遇到這樣的問題: 你是如何理解TCP/IP協議的?
回答:通訊協議?三次握手 ? 四次揮手? 一臉懵逼!
如果你感覺已經被上述情景安排,那麼有必要好好看看這篇文章。
協議實際上就是一種約定。好比說,我們做一個石頭剪刀布的遊戲,我們約定好:石頭>剪刀、剪刀>布、布>石頭,以此作為遊戲規則。我們所有人都遵循這個約定,那麼就不需要任何的多餘的溝通便可以完成這個遊戲。而這種方式形成的約定實際上就是一種協議了。
話聯網早期時,儘管知道計算機連接的原理,但是沒有協議的時候,就沒有辦法進行大規模的通信使用。當時就衍生出了很多為了解決當時問題的協議,像TCP協議就是為了約定大家使用TCP連接時傳輸的一種協議,HTTP協議則是為了約定文本傳輸的一種協議。
而TCP/IP協議並不是指某一個具體的協議,它是指代一系列的協議棧,因此也叫TCP/IP協議棧或者TCP/IP協議簇。
所以廣義上,我們說的TCP/IP指的是4層的總和。 而狹義上來說,指的是4層中的傳輸層和網絡互聯層。
在 TCP/IP協議簇 中,定義了包含對應 OSI 模型的每一層。但同時對 OSI 模型層做了簡化處理。看看這種圖理解一下:
TCP/IP層和OSI參考模型層的對應關係
也即是OSI模型中的7層,在TCP/IP中使用4層代替了。沒辦法,誰讓OSI那麼複雜呢。
在TCP/IP協議簇中每一層都有對應的協議,最終組成協議簇。
TCP/IP協議棧每一層的協議
我們經常說的TCP和UDP在協議棧的傳輸層,而IP協議則在協議棧的網絡互聯層。還有經常被問到的HTTP協議實際上在協議棧的應用層。
TCP/IP協議棧被分作這麼多的層級,目的是為了整理硬體間通信時的一個通用的模型,因此它們每一層都和其上下層有關聯性的,如下圖:
TCP/IP協議棧數據封包分層
上面就是"TCP/IP協議"的總體概念了。但是其內部還有這麼多的協議,這裡挑幾個常見的講一講,從底層到上層:
IP協議 TCP協議 UDP協議 HTTP協議
IP協議處於TCP/IP協議簇的網絡互聯層。它提供不可靠、無連接的服務,也即依賴其他層的協議進行差錯控制。在區域網環境,IP協議往往被封裝在乙太網幀中傳送。而所有的TCP、UDP、ICMP、IGMP數據都被封裝在IP數據報中傳送。
在IP協議中,有兩個重要的內容需要了解下。一是IP位址的概念,二是IP協議的報頭。
其實對於IP位址我們日常接觸還是挺多的。它給每一個接入網際網路的計算器一個地址,從而使得其他的計算機能夠訪問到它。與此同時,當計算機有了地址之後,才能遵循IP協議,和其他的計算機進行數據的傳遞。
目前有兩種IP版本,分別是IPV4和IPV6。IPV4占用8個位元組32bit,而IPV6則是32個位元組128bit。IPV6的可用的數量極其龐大,大到全球每一粒沙子都可以分配一個IPV6地址。
以IPV4為例, IPV4的32bit地址中,分為兩個部分:網絡號和主機號。同時根據不同的內容開頭,又分為A、B、C、D、E類。
IPV4
網絡號用於區分不同的網絡點,比如一個公司是一個網絡集群,我們可以通過他的網絡號確定該公司網關,再通過主機號確定每一台計算。
假如一個C類的IP位址類型,包含了21位網絡號,實際上就能區分出 2^21 個網絡號,而在每一個網絡號中,可以區分 2^8 -2 = 254(起始的網絡號地址和最後一個為廣播地址都不可用於主機)個主機號。如果一個網吧採用這種方式的話,那麼他最多能安裝254台機器。如果我們想要得到更多的主機號,應該延長主機號的位數,但是相應的,網絡號的數量將減少,因為兩者的總長度是不變的。
通過掩碼能夠改變網絡號和主機號的位數。
通常,我們看到的掩碼類似:
255.255.255.0
二進位表示:
11111111.11111111.11111111.00000000
如果一個IPV4地址為:192.168.1.12
那麼IP位址和掩碼經過與運算之後的結果為:192.168.1.0(192.168.001.000), 這就是我們常說的網關!
而從 192.168.1.1~192.168.1.254都可作為主機號。也即是這個網關下,可以容納 254 台機器。
如果將掩碼更改為:
255.255.254.0
二進位表示:
11111111.11111111.11111110.00000000
那麼與運算的結果為:192.168.0.0 ,這時候可以使用的主機號就變成了 192.168.0.0 ~ 192.168.1.254, 即可容納 510 台機器。
當一個 IP 包從一台計算機被發送,它會到達一個 IP 路由器。
IP 路由器負責將這個包路由至它的目的地,直接地或者通過其他的路由器。
在一個相同的通信中,一個包所經由的路徑可能會和其他的包不同。而路由器負責根據通信量、網絡中的錯誤或者其他參數來進行正確地尋址。
在上面的數據分層中,我們看到IP協議的構成實際上是 IP報頭 + TCP協議內容。
因此決定一個IP協議屬性的的關鍵是 IP報頭的內容。
下面我們來看下IP協議的組成,IPV4中普通的IP首部長20個位元組。其中有32位的源IP位址和32位的目的IP位址。
TTL:生存時間。代表了數據包可以經過的最多路由器數。比如TTL為10,意思是如果經過10次路由器轉發,仍然未找到目的地址,則報文丟棄
8位協議指示的是傳輸層承載的協議
16位總長度:指IP數據包的最大長度。16bit那麼最長可達65535位元組。但是通過鏈路的MTU不會有這麼大。因此如果數據包長度超過了MTU,數據包會被分片。如果發生了分片,則需要用到16位標識以及13位片偏移來找到分片的報文。
IP協議報頭
TCP協議位於協議棧的傳輸層。當應用層向TCP層發送用於網間傳輸的、用8位位元組表示的數據流,TCP則把數據流分割成適當長度的報文段,最大傳輸段大小(MSS)通常受該計算機連接的網絡的數據鏈路層的最大傳送單元(MTU)限制。之後TCP把數據包傳給IP層,由它來通過網絡將包傳送給接收端實體的TCP層。
TCP為了保證報文傳輸的可靠,就給每個包一個序號,同時序號也保證了傳送到接收端實體的包的按序接收。然後接收端實體對已成功收到的位元組發回一個相應的確認(ACK);如果發送端實體在合理的往返時延(RTT)內未收到確認,那麼對應的數據(假設丟失了)將會被重傳。
在擁塞控制上,採用廣受好評的TCP擁塞控制算法(也稱AIMD算法)。
該算法主要包括三個主要部分:
(1)加性增、乘性減;
(2)慢啟動;
(3)對超時事件做出反應。
和IP協議一樣,TCP協議也有他的報頭部分。
以下即是圖示:
TCP報頭
標誌位,標誌位主要用戶標誌該報文當前的狀態。
URG:指示報文中有緊急數據,應儘快傳送(相當於高優先級的數據)。 ACK:確認序號(AN)有效。 PSH:接到後儘快交付給接收的應用進程。 RST:TCP連接中出現嚴重差錯(如主機崩潰),必須釋放連接,在重新建立連接。 SYN:處於TCP連接建立過程。 FIN:發送端已完成數據傳輸,請求釋放連接。
TCP是一個面向連接的協議,在每一次傳輸數據前,客戶端和服務端需要進行連接,這個連結就是著名的三次握手。
第一次:客戶端向服務端發送一個 SYN(SEQ=x 客戶端序號)報文給伺服器端,進入SYN_SEND狀態。
第二次:伺服器端收到SYN報文,回應一個SYN (SEQ=y 服務端序號)ACK(ACK=x+1 確認號=客戶端序號+1)報文,進入SYN_RECV狀態。
第三次:客戶端收到伺服器端的SYN報文,回應一個ACK(ACK=y+1)報文,進入Established狀態。
圖解:
TCP的三次握手
思考:為什麼要進行三次握手,而不是兩次呢? 比如在第一次握手之後,伺服器進入準備狀態,然後發送消息給客戶端,客戶端也進入準備狀態,這就完成了雙方的確認了。
思考2:三次握手就很安全了嗎?
#netstat -nap | grep SYN_RECV
既然TCP面向連接,那麼肯定也有斷開連接的操作。一個TCP完整的斷開需要進行四次揮手。
第一次:客戶端向服務端發送 FIN + ACK 報文,同時攜帶序號為 X。 客戶端進入 FIN-WAIT1
第二次:伺服器端回復 ACK 報文。附帶序號Z和確認序號X+1,表示伺服器已經接受到了客服端的報文。但是由於伺服器可能還在處理事務,因此,報文並不會攜帶FIN標誌。狀態:CLOSE WAIT
第三次:在一段時間之後,伺服器已經處理完畢,發送帶有 FIN和ACK的報文,序號為Y,確認序號為 X + 1 。 狀態: ACK-LAST
第四次:客戶端發送ACK報文,序號為 X+1,確認號Y+1 。 客戶端進入: TIME_WAIT。服務端進圖CLOSE(初始狀態)
TCP四次揮手
思考:為什麼建立連接是三次握手,而關閉連接卻是四次揮手呢?
思考:為什麼TIME_WAIT狀態需要經過2MSL(最大報文段生存時間)才能返回到CLOSE狀態?
UDP協議全稱是用戶數據報協議,在網絡中它與TCP協議一樣用於處理數據包,兩者同處於協議棧的傳輸層,和TCP不同的是,UDP是一種無連接的協議。
因為UDP是無連接的,所以相對來說,UDP的報頭比TCP要簡單多了。
UDP報頭
UDP 特點
(1) UDP是一個非連接的協議,傳輸數據之前源端和終端不建立連接,當它想傳送時就簡單地去抓取來自應用程式的數據,並儘可能快地把它扔到網絡上。在發送端,UDP傳送數據的速度僅僅是受應用程式生成數據的速度、計算機的能力和傳輸帶寬的限制;在接收端,UDP把每個消息段放在隊列中,應用程式每次從隊列中讀一個消息段。
(2) 由於傳輸數據不建立連接,因此也就不需要維護連接狀態,包括收髮狀態等,因此一台服務機可同時向多個客戶機傳輸相同的消息。
(3) UDP信息包的標題很短,只有8個位元組,相對於TCP的20個位元組信息包的額外開銷很小。
(4) 吞吐量不受擁擠控制算法的調節,只受應用軟體生成數據的速率、傳輸帶寬、源端和終端主機性能的限制。
(5)UDP使用盡最大努力交付,即不保證可靠交付,因此主機不需要維持複雜的連結狀態表(這裡面有許多參數)。
(6)UDP是面向報文的。發送方的UDP對應用程式交下來的報文,在添加首部後就向下交付給IP層。既不拆分,也不合併,而是保留這些報文的邊界,因此,應用程式需要選擇合適的報文大小。
我們經常使用「ping」命令來測試兩台主機之間TCP/IP通信是否正常,其實「ping」命令的原理就是向對方主機發送UDP數據包,然後對方主機確認收到數據包,如果數據包是否到達的消息及時反饋回來,那麼網絡就是通的。
HTTP協議名為超文本傳輸協議。這個協議在 TCP/IP 協議棧的應用層,因此我們無需操心HTTP是如何傳輸的,只需要關心,我們傳輸的內容,能否正確的被接收端識別。
HTTP 基於TCP實現,簡單來說,TCP協議負責可靠的內容傳輸,HTTP協議負責識別內容,兩者本身不在一個層面,沒有可比行。
HTTP無狀態的意思是,每一次的內容解析是沒有關聯的。TCP有狀態是指兩端在連接過程的。
HTTP包含兩種報文類型:請求報文、響應報文。請求報文用在客戶端對伺服器的請求時使用的報文格式,響應用在伺服器響應請求的報文格式。
客戶端發送一個HTTP請求到伺服器的請求消息包括以下格式:請求行(request line)、請求頭部(header)、空行和請求數據四個部分組成,下圖給出了請求報文的一般格式。
HTTP請求消息體結構
HTTP消息體主要包含以下實質內容(空格和換行也必不可少):
請求方法 URL:統一資源定位符 HTTP請求頭部 HTTP請求體
以下是一個HTTP請求的例子:
HTTP請求實例
HTTP包含了多種不同的請求方式,每一種請求方式用在不同的場景。
HTTP請求方法
URL由三部分組成:資源類型、存放資源的主機域名、資源文件名。
URL的一般語法格式為:
(帶方括號[]的為可選項):
protocol :// hostname[:port] / path / [;parameters][?query]#fragment
舉個例子: https://baijiahao.baidu.com/s?id=1603848351636567407&wfr=spider&for=pc
protocol:https
hostname:baijiahao.baidu.com
parameters:id=1603848351636567407&wfr=spider&for=pc (使用&分割參數)
總結一下如下圖:
附一張解析圖
請求頭中主要包含本次請求的附加信息,其中常用的欄位如:
在整個報文中,請求頭之後,隔一行空格,以下部分就是HTTP的請求體了。
請求體是我們發送請求的時候需要傳給接收端的內容。其格式需要和請求頭中的Content-Type對應。不然會導致接受無法識別。
如上圖中的請求體: name=tom&password=1234
HTTP的響應同樣分為:響應行、響應頭、響應體。和請求報文有點類似。
總體結構如圖:
HTTP響應報文
響應行中包含了HTTP的版本和本次請求的狀態。請求狀態的對應值見 HTTP響應碼大全.
響應頭用於描述伺服器的基本信信息、數據的描述,這些信息將告知客戶端如何處理響應題中的內容。
響應實體中包含的就是客戶端從伺服器中獲取的數據了。數據的格式和長度都會在響應體頭中描述。
除了 TCP/IP 協議棧的內容之外,還要諸如 Scoket 、 HTTPS 協議等內容沒有再本文中介紹。主要是因為其他的內容相對來說形成一套體系,內容較多,將會在後續的文章中介紹。
小編整理了一些B-樹,B+樹的資料如下:
如果你也對Linux後台伺服器開發感興趣,想學習這方面的技術,後台私信【學習】免費獲取小編整理的一些資料(關注才能私信)