最近又重溫了TCP/IP的知識,果真比第一次看的時候有感悟多了,那就寫一點東西來總結一下。程序員
如今咱們主要了解計算機網絡的兩種模型:OSI模型和TCP/IP模型。須要注意的是因爲OSI模型過於複雜致使難以實現,所以致使TCP/IP模型更早地應用在現實中。這也使得TCP/IP模型成爲事實上的標準,而OSI僅僅是紙面上的標準。服務器
在OSI模型中,將計算機網絡分紅了7層,而在TCP/IP模型中則分紅了4層,其各層對應關係以下表所示:網絡
OSI | TCP/IP | 對應網絡協議 | 所在位置 |
應用層 | 應用層 | TFTP, FTP, NFS, WAIS | 主機 |
表示層 | Telnet, Rlogin, SNMP, Gopher | ||
會話層 | SMTP, DNS | ||
傳輸層 | 傳輸層 | TCP, UDP | |
網絡層 | 網際層 | IP, ICMP, ARP, RARP, AKP, UUCP | 媒介 |
數據鏈路層 | 網絡接口層 | FDDI, Ethernet, Arpanet, PDN, SLIP, PPP | |
物理層 | IEEE 802.1A, IEEE 802.2到IEEE 802.11 |
在整個計算機網絡體系中,最核心的當屬是位於傳輸層的TCP與UDP協議了。由於他們位於主機協議棧的最底層,向上方應用層提供不一樣的數據交付方式。spa
由於UDP協議相對TCP協議來講相對簡單,就先回顧一下UDP協議。計算機網絡
UDP的全稱也叫作用戶數據報協議(User Datagram Protocal),它有如下幾個值得注意的特色:3d
UDP不能保證可靠傳輸,也就更不能保證所發送的數據的到達順序,它所實現的是盡最大的努力交付。指針
UDP是面向數據報文的、無鏈接的協議,所以它的開銷低而且發送器前的時延小(由於不用創建鏈接啊),面向報文也使得IP層在傳輸UDP協議的報文時既不會拆分也不會合並。視頻
UDP能夠支持一對1、一對多、多對1、多對多的通訊。blog
UDP沒有擁塞控制功能,它的發送速率不會隨着網絡出現的擁塞而下降,因此它的實時性較好。這也是許多視頻聊天應用採用它的緣由。接口
以下是UDP報文頭部格式
其中從1到8字節分別是來源端口號、目的端口號、報文長度、檢驗和,每一個字段各佔兩字節。
UDP的通訊方式較爲簡單,發送端發送完一個報文繼續發送下一個,待將全部報文發送完畢通訊就結束了。
接收方也是如此。
傳輸控制協議(英語:Transmission Control Protocol,縮寫爲 TCP)是一種面向鏈接的、可靠的、基於字節流的傳輸層通訊協議。
TCP協議所要實現的功能是端到端之間的可靠傳輸,所以,相較於UDP協議而言,TCP協議要複雜的多。
相對於UDP協議,TCP協議有下面的幾個特色:
TCP協議保證可靠傳輸,也就是說發送的數據是什麼樣,接收的數據也是什麼樣。
TCP協議是有鏈接的、面向數據流的協議。有鏈接是說數據傳送前通訊雙方須要創建鏈接、通訊完畢後須要斷開鏈接,不過這裏所提到的鏈接都是邏輯上的鏈接。面向數據流的意思是說發送方應用程序發送的數據是什麼順序,接收方應用讀取的接收到的數據也是什麼順序。
TCP協議提供的是端到端的通訊,也就是說一條TCP鏈接只能提供一對一的通訊。不過,一個應用能夠同時創建多條TCP鏈接來實現與多個目標的通訊。
TCP協議提供擁塞控制功能,會在網絡情況良好的狀況下適當提升發送/接收速率,反之則適當下降發送/接收速率。這樣,將會提升對網絡的利用率。
此外,還須要注意的是,TCP提供的是全雙工的通訊。
要理解TCP協議中各功能的實現,要先從TCP的數據封包結構開始。
下面的圖片就是TCP數據封包的結構示意圖:
各個字段功能以下:
來源端口(2字節):標識來源端口號。
目的端口(2字節):標識目的端口號。
序列號碼(4字節):代表此封包在字節流中的順序號。由於TCP是面向字節流的協議,須要保證最終的數據順序與發送方發送的順序一致,因此須要這個字段來代表該封包在字節流中的位置。
確認號碼(4字節):對此前按順序收到的最後一個封包的序列號碼的確認。
例如:當33號之前的封包都已經完整的到達了後,就向發送方發送確認號碼爲34(確認的封包號碼+1)來告訴發送方:33號之前的全部封包我都已經收到了,能夠向我發送34號封包了。
這裏要注意: 若是收到了3四、3五、37號封包而未收到36號封包,則向發送端發送確認號爲35的封包。
總之要記住,確認號=N,表示N-1及其以前的封包都已經收到。
報頭長度(1字節):指示報文頭部的長度。
可是須要注意,這裏的單位是4字節。例如,這個屬性的值是15的話則說明報文頭部的長度是60(15*4)字節。
保留字段(10位):暫時沒打算好乾啥用,一概置0。
標識符(6位):每一個比特位分別表示以下標識符:
URG—爲1表示高優先級數據包,緊急指針字段有效。
ACK—爲1表示確認號字段有效。TCP規定鏈接創建後,全部傳送的報文段都必須把該字段置爲1。
PSH—爲1表示是帶有PUSH標誌的數據,指示接收方應該儘快將這個報文段交給應用層而不用等待緩衝區裝滿。
RST—爲1表示出現嚴重差錯。可能須要重現建立TCP鏈接。還能夠用於拒絕非法的報文段和拒絕鏈接請求。
SYN—爲1表示這是鏈接請求或是鏈接接受請求,用於建立鏈接和使順序號同步
FIN—爲1表示發送方沒有數據要傳輸了,要求釋放鏈接。
窗口(2字節):表示從確認號開始,本報文的源方能夠接收的字節數,即源方接收窗口大小。用於流量控制。
校驗和(2字節)對整個的TCP報文段,包括TCP頭部和TCP數據,以16位字進行計算所得。這是一個強制性的字段。
緊急指針(2字節):本報文段中的緊急數據的最後一個字節的序號。
選項字段(最多40字節):每一個選項的開始是1字節的kind字段,說明選項的類型。
其中上面的三、四、七、8是重點。
爲了搞明白下面要說的TCP的一些機制,首先須要知道TCP協議可以實現可靠傳輸的一個基本的原理--超時重傳。
說來很簡單,其實就是收到當接收方收到一個數據封包的時候就向發送方發送一個確認數據封包。而當發送方發送完一個數據封包通過一段時間沒有收到接收方的確認封包時,就會將上一個封包再次向接收方發送一次。
固然,TCP中真正的機制比這個要複雜的多,可是基於的原理都是同樣的。
在說TCP鏈接以前先插播一個小故事。
說是有一天,一個程序員到酒吧去喝酒,因而跟服務員之間發生了以下的對話。
程序員:我要一瓶酒。
服務員:你肯定你要一瓶酒?
程序員:我肯定我要一瓶酒。
因而服務員就給了程序員一瓶酒。
是否是很羅嗦?沒錯,這就是典型的TCP鏈接創建的過程。以下面的圖:
圖中的小人就是客戶端,另外一邊不用說也知道就是服務器端。圖中畫的比較簡略,大概過程是下面這樣:
下面過程當中,ACK表示上面說的TCP包頭中的確認標識,ack表示確認號(4字節那個)。
客戶端向服務器發送創建鏈接請求數據包,其中包頭內容SYN=1,seq=x(本身隨機挑選的起始序號)。(我要一瓶酒)
服務器收到請求後,若是贊成創建鏈接,就向客戶端發送贊成創建鏈接請求數據封包,其包頭內容SYN=1,ACK=1,ack=x+1(還記得爲何嗎),seq=y(一樣也是本身隨機挑選的)。(你肯定你要一瓶酒嗎)
客戶端收到服務器發來的確認請求後,也向服務器發送確認封包,其內容ACK=1,ack=y+1(原理同上),seq=x+1(畢竟已經發送過seq=x的封包了),隨後客戶端就進入鏈接創建狀態,而服務器就在收到這個確認封包後也進入鏈接創建狀態。(我肯定我要一瓶酒)
以上步驟就是俗稱的「TCP三次握手」。
固然,最初的時候服務器確定是處於監聽狀態啦,要否則怎麼可以對客戶端的數據封包作出迴應呢。
要注意的是,這裏有個很經典的問題就是爲何在收到服務器的確認封包後還要再向服務器發送一個確認封包呢?
這主要是由於TCP協議的下層網絡是不可靠的,也就是說數據封包可能丟失也可能滯留在某個節點很長時間。
因此這就有一種可能就是客戶端發送給服務器的封包在網絡中滯留了,這樣客戶端固然也就不會收到服務器發來的確認封包。還記得TCP有個超時重傳機制嗎?沒錯,這個時候客戶端是覺得本身發出去的封包在網絡中是丟了的,因而過一段時間又會重傳剛纔的封包。
幸運的是,此次重傳的封包十分順利的到達了服務器,因而服務器也十分順利的向客戶端發出了確認封包。原本就要愉快的創建鏈接了,但是天有不測風雲,剛纔滯留的請求封包此時到達了服務器這裏。
這個時候服務器就懵了,這究竟是客戶端又要跟我創建一次鏈接仍是剛纔滯留的封包又給了我呢?
因而這個時候就須要客戶端再發送一個確認封包給服務器了。
固然,有鏈接創建,就有鏈接釋放,客戶端與服務器之間的鏈接釋放過程大概是下面這個樣子的。
跟創建鏈接的時候差很少,大概過程大概向下面這樣:
客戶端向服務器發送鏈接請求釋放封包,封包內容爲FIN=1,seq=u。
服務器收到後,決定要跟客戶端釋放鏈接,但是還有數據沒傳送完啊,就先發一個封包告訴客戶端我能夠釋放鏈接,你能夠不用向我發送數據了,但是我還有數據沒有傳送完,因此在我告訴你結束以前你得一直接收個人數據(別忘了,TCP但是全雙工的)。因此所發送封包內容爲:ACK=1,ack=u+1,seq=v。(FIN=0表示我還有數據要發送)
服務器發送完數據後,告訴客戶端我都發送完了,能夠結束了。因而發送封包爲FIN=1,ACK=1,ack=u+1(這裏得注意啦),seq=w(中間還傳輸過數據,因此可能不是v+1)。
客戶端收到服務器的確認後,再次向服務器發送確認,內容是ACK=1,ack=w+1,seq=u+1。
發送完上面的確認封包後,客戶端再等一段時間(2MSL)後,就斷開鏈接。至此,鏈接正常釋放。
如上步驟就是俗稱的「TCP4次揮手」。
這裏之因此是4次,主要是與創建鏈接時相比,服務器的確認和結束被分紅了兩個封包分別發送了出去。
固然,這裏也有個比較經典的問題就是客戶端爲何在發送完最後一個封包後還要再等待一段時間?
這裏也主要是由於TCP協議下層的網絡並非很可靠,有可能客戶端發出的最後一個封包在路上丟了而致使服務器等待很長世間浪費服務器資源。因而就讓客戶端再等待一段時間,這樣當服務器收不到客戶端發來的確認封包時,還會再重傳一個鏈接結束封包,此時的客戶端再次受到這個鏈接結束封包後還能夠再重傳一次確認封包來讓服務器正常結束鏈接。這樣,就不會白白浪費服務器資源了。
最後,再從整個網絡的範圍來看,一個數據封包究竟是要通過怎樣的旅程纔會從出發地到達目的地呢?
以TCP協議爲例,當TCP協議接到上層應用層交付下來的數據封包後,就在這個數據封包的前面加上TCP的頭部。
而後,再交付給下層的網絡層。
網絡層接收到上層傳輸層傳遞下來的封包後,就在封包的頭部加上IP協議的頭部和網際接口層的首部和頭部後通過層層路由,最終到達距離目的主機最近的路由器。
而後距離目的主機最近的路由器再對數據包進行解包,去掉網際接口層和網絡層的封裝後將數據包送到目的主機的傳輸層(TCP接收緩衝池),再由目的主機的傳輸層交給上層的應用層。
一圖以蔽之: