Linux網(wǎng)絡(luò)-UDP/TCP協(xié)議詳解
2023/10/17 14:32:49
Linux網(wǎng)絡(luò)-UDP/TCP協(xié)議詳解
- 零、前言
- 一、UDP協(xié)議
- 二、TCP協(xié)議
-
- 1、應(yīng)答機制
- 2、序號機制
- 3、超時重傳機制
- 4、連接管理機制
-
- 三次握手
- 四次揮手
- 5、理解CLOSE_WAIT狀態(tài)
- 6、理解TIME_WAIT狀態(tài)
- 7、流量控制
- 8、滑動窗口
-
- 丟包問題
- 9、擁塞控制
- 10、延遲應(yīng)答
- 11、捎帶應(yīng)答
- 12、面向字節(jié)流
- 13、粘包問題
- 14、TCP異常情況
- 14、TCP異常情況
零、前言
本章主要講解傳輸層協(xié)議UDP及TCP相關(guān)的內(nèi)容
一、UDP協(xié)議
- UDP協(xié)議端格式:
- 說明:
16位源端口號:表示數(shù)據(jù)從哪里來
16位目的端口號:表示數(shù)據(jù)要到哪里去
16位UDP長度:表示整個數(shù)據(jù)報(UDP首部+UDP數(shù)據(jù))的長度
16位UDP檢驗和:如果UDP報文的檢驗和出錯,就會直接將報文丟棄
注:端口號大部分都是16位的,其根本原因就是因為傳輸層協(xié)議當中的端口號就是16位的
- UDP如何將報頭與有效載荷進行分離:
UDP報頭是一種定長報頭,UDP在讀取報文時讀取完前8個字節(jié)(報頭)后剩下的就都是有效載荷了
- UDP如何將有效載荷交付給上層協(xié)議:
獲取到一個報文后從該報文的前8個字節(jié)中提取出對應(yīng)的目的端口號,通過目的端口號找到對應(yīng)的上層應(yīng)用層進程進行交付
- UDP的特點:
無連接: 知道對端的IP和端口號就直接進行傳輸, 不需要建立連接
不可靠: 沒有確認機制, 沒有重傳機制,無法保證接收報文的正確順序; 如果因為網(wǎng)絡(luò)故障該段無法發(fā)到對方, UDP協(xié)議層也不會給應(yīng)用層返回任何錯誤信息
面向數(shù)據(jù)報: 不能夠靈活的控制讀寫數(shù)據(jù)的次數(shù)和數(shù)量
- 對于面向數(shù)據(jù)報的理解:
應(yīng)用層交給UDP多長的報文, UDP原樣發(fā)送, 既不會拆分, 也不會合并
用UDP傳輸100個字節(jié)的數(shù)據(jù):如果發(fā)送端調(diào)用一次sendto, 發(fā)送100個字節(jié), 那么接收端也必須調(diào)用對應(yīng)的一次recvfrom, 接收100個字節(jié); 而不能循環(huán)調(diào)用10次recvfrom, 每次接收10個字節(jié)
- UDP的發(fā)送和接收緩沖區(qū):
UDP沒有真正意義上的發(fā)送緩沖區(qū),調(diào)用sendto會直接交給內(nèi)核,由內(nèi)核將數(shù)據(jù)傳給網(wǎng)絡(luò)層協(xié)議進行后續(xù)的傳輸動作
UDP具有接收緩沖區(qū),但是這個接收緩沖區(qū)不能保證收到的UDP報的順序和發(fā)送UDP報的順序一致; 如果緩沖區(qū)滿了, 再到達的UDP數(shù)據(jù)就會被丟棄
如果沒有接收緩沖區(qū),那么就要求上層及時將獲取到的報文讀取上去,如果沒有及時被讀取,那么新獲取的報文數(shù)據(jù)就會被迫丟棄;UDP會維護接收緩沖區(qū)將接收到的報文暫時的保存起來,供上層讀取
- UDP是全雙工通信:
UDP的socket在讀(寫)的同時也能進行寫(讀),也就是說不會像管道這種半雙工通信讀寫是阻塞進行的(無法同時進行)
- UDP使用注意事項:
- UDP協(xié)議首部中有一個16位的最大長度,也就是說一個UDP能傳輸?shù)臄?shù)據(jù)最大長度是64K(包含UDP首部)
- 如果我們需要傳輸?shù)臄?shù)據(jù)超過64K, 就需要在應(yīng)用層手動的分包,多次發(fā)送,并在接收端手動拼裝
- 基于UDP的應(yīng)用層協(xié)議:
- NFS:網(wǎng)絡(luò)文件系統(tǒng)
- TFTP:簡單文件傳輸協(xié)議
- DHCP:動態(tài)主機配置協(xié)議
- BOOTP:啟動協(xié)議(用于無盤設(shè)備啟動)
- DNS:域名解析協(xié)議
- 關(guān)于可靠性的理解:
計算機中的硬件設(shè)備是之間的數(shù)據(jù)傳輸是依靠“線”進行的,而這些硬件設(shè)備都在一臺機器上,因此傳輸數(shù)據(jù)的“線”是很短的,傳輸出錯的概率也非常低
如果要在網(wǎng)絡(luò)中進行通信(距離遠),此時需要維護傳輸?shù)摹熬€”就非常長,傳輸出錯的概率增大,要保證傳輸?shù)目煽啃跃托枰鄳?yīng)的做更多的事情,而TCP就是一種保證可靠性的協(xié)議
- UDP協(xié)議存在的意義:
- TCP協(xié)議是可靠的協(xié)議,也就意味著TCP協(xié)議需要做更多的工作來保證傳輸數(shù)據(jù)的可靠,此時需要的成本相比于UDP更高
- UDP協(xié)議是不可靠的協(xié)議,也就意味著UDP協(xié)議不需要考慮數(shù)據(jù)傳輸時可能出現(xiàn)的問題,但UDP無論是使用還是維護都足夠簡單
- 雖然TCP復(fù)雜,但TCP的效率不一定比UDP低,TCP當中不僅有保證可靠性的機制,還有保證傳輸效率的其他機制
- 網(wǎng)絡(luò)通信時具體采用TCP還是UDP完全取決于上層的應(yīng)用場景。如果應(yīng)用場景嚴格要求數(shù)據(jù)在傳輸過程中的可靠性,那么就必須采用TCP協(xié)議,如果應(yīng)用場景允許數(shù)據(jù)傳輸出現(xiàn)少量丟包,那么肯定優(yōu)先選擇UDP協(xié)議,因為UDP協(xié)議足夠簡單
二、TCP協(xié)議
TCP全稱為 “傳輸控制協(xié)議(Transmission Control Protocol”). 人如其名, 要對數(shù)據(jù)的傳輸進行一個詳細的控制
- TCP協(xié)議段格式:
- 說明:
16位源端口號:表示數(shù)據(jù)從哪里來
16位目的端口號:表示數(shù)據(jù)要到哪里去
32位序號:表示發(fā)送的TCP報文的編號
32位確認序號:表示對接收到對方曾經(jīng)發(fā)送過的TCP報文的確認
4位TCP報頭長度:表示該TCP報頭的長度,以4字節(jié)為單位(表示范圍20-60字節(jié):固定的字段就有20字節(jié),如果帶有選項的話,最大報頭可以為15*4=60字節(jié))
6位保留字段:TCP報頭中暫時未使用的6個比特位
16位窗口大?。罕WCTCP可靠性機制和效率提升機制的重要字段
16位檢驗和:由發(fā)送端填充,采用CRC校驗;接收端校驗不通過,則認為接收到的數(shù)據(jù)有問題(檢驗和包含TCP首部+TCP數(shù)據(jù)部分)
16位緊急指針:標識緊急數(shù)據(jù)在報文中的偏移量,需要配合標志字段當中的URG字段統(tǒng)一使用
TCP報頭當中的6位標志位:
URG:緊急指針是否有效
ACK:確認序號是否有效
PSH:提示接收端應(yīng)用程序立刻將TCP接收緩沖區(qū)當中的數(shù)據(jù)讀走
RST:表示要求對方重新建立連接。我們把攜帶RST標識的報文稱為復(fù)位報文段
SYN:表示請求與對方建立連接。我們把攜帶SYN標識的報文稱為同步報文段
FIN:通知對方,本端要關(guān)閉了。我們把攜帶FIN標識的報文稱為結(jié)束報文段
- TCP如何將報頭與有效載荷進行分離:
獲取到TCP報文后,首先讀取報文的前20個字節(jié),并從中提取出4位的首部長度,此時便獲得了TCP報頭的大小,讀取完TCP的基本報頭和選項字段后,剩下的就是有效載荷了
- TCP具有發(fā)送和接收緩沖區(qū):
- 通過發(fā)送緩沖區(qū)存儲發(fā)送的數(shù)據(jù),當收到對應(yīng)的應(yīng)答后(也就是對應(yīng)的數(shù)據(jù)成功被對端接收),對應(yīng)的數(shù)據(jù)才會‘取出’,也就保證了發(fā)送的可靠性;通過接收緩沖區(qū)儲存接收到的數(shù)據(jù),保證數(shù)據(jù)能夠可靠的被上層取出
- 調(diào)用write/send這樣的系統(tǒng)調(diào)用接口時,實際不是將數(shù)據(jù)直接發(fā)送到了網(wǎng)絡(luò)當中,而是將數(shù)據(jù)從應(yīng)用層拷貝到了TCP的發(fā)送緩沖區(qū)當中;當上層調(diào)用read/recv這樣的系統(tǒng)調(diào)用接口時,實際也不是直接從網(wǎng)絡(luò)當中讀取數(shù)據(jù),而是將數(shù)據(jù)從TCP的接收緩沖區(qū)拷貝到了應(yīng)用層這樣能夠使得應(yīng)用層能夠和傳輸層進行解耦,上層只需要將數(shù)據(jù)交給TCP或者從TCP中將數(shù)據(jù)取出,TCP則是負責數(shù)據(jù)的發(fā)送和接收的問題
- 16位窗口大?。?/li>
當發(fā)送端要將數(shù)據(jù)發(fā)送給對端時,本質(zhì)是把自己發(fā)送緩沖區(qū)當中的數(shù)據(jù)發(fā)送到對端的接收緩沖區(qū)當中,但緩沖區(qū)是有大小的,不能無限制的接收,所以需要對發(fā)送進行控制
而16位窗口大小當中填的是自身接收緩沖區(qū)中剩余空間的大小,當對端接收到窗口信息時可以根據(jù)這個字段來調(diào)整自己發(fā)送數(shù)據(jù)的速度,避免發(fā)送速度過快造成緩沖區(qū)滿足,進而可能引起丟包重傳
用read/recv函數(shù)從套接字當中讀取數(shù)據(jù)時,會因為套接字當中沒有數(shù)據(jù)而被阻塞住,本質(zhì)是因為TCP的接收緩沖區(qū)當中沒有數(shù)據(jù)了,實際是阻塞在接收緩沖區(qū)當中了;調(diào)用write/send函數(shù)往套接字中寫入數(shù)據(jù)時,會因為套接字已經(jīng)寫滿而被阻塞住,本質(zhì)是因為TCP的發(fā)送緩沖區(qū)已經(jīng)被寫滿了,實際是阻塞在發(fā)送緩沖區(qū)當中了
- 六個標志位:
TCP報文除了正常通信時發(fā)送的普通報文,還需要其他類型的報文來表示其他的一些需求,例如連接,斷開連接等等;TCP使用報頭當中的六個標志字段來進行區(qū)分的報文類型,這六個標志位都只占用一個比特位,為0表示假,為1表示真
SYN:報文當中的SYN被設(shè)置為1,表明該報文是一個連接建立的請求報文;只有在連接建立階段,SYN才被設(shè)置,正常通信時SYN不會被設(shè)置
ACK:報文當中的ACK被設(shè)置為1,表明該報文可以對收到的報文進行確認;一般除了第一個請求報文沒有設(shè)置ACK以外,其余報文基本都會設(shè)置ACK,因為發(fā)送出去的數(shù)據(jù)本身就對對方發(fā)送過來的數(shù)據(jù)的確認
FIN:報文當中的FIN被設(shè)置為1,表明該報文是一個連接斷開的請求報文;只有在斷開連接階段,F(xiàn)IN才被設(shè)置,正常通信時FIN不會被設(shè)置
URG:TCP是保證數(shù)據(jù)按序到達的,對于若干個TCP報文進行發(fā)送,最終到達接收端時這些數(shù)據(jù)也都是有序的,對于發(fā)送“緊急數(shù)據(jù)”就需要讓對方上層提取進行加急處理;當URG標志位被設(shè)置為1時,需要通過TCP報頭當中的16位緊急指針來找到緊急數(shù)據(jù),否則一般情況下不需要關(guān)注TCP報頭當中的16位緊急指針,16位緊急指針代表的就是緊急數(shù)據(jù)在報文中的偏移量
注:recv函數(shù)的第四個參數(shù)flags有一個叫做MSG_OOB的選項可供設(shè)置,其中OOB是帶外數(shù)據(jù)(out-of-band)的簡稱,帶外數(shù)據(jù)就是一些比較重要的數(shù)據(jù),因此上層如果想讀取緊急數(shù)據(jù),就可以在使用recv函數(shù)進行讀取,并設(shè)置MSG_OOB選項;send函數(shù)的第四個參數(shù)flags也提供了一個叫做MSG_OOB的選項,上層如果想發(fā)送緊急數(shù)據(jù),就可以使用send函數(shù)進行寫入,并設(shè)置MSG_OOB選項
PSH:報文當中的PSH被設(shè)置為1,是在告訴對端盡快將緩沖區(qū)里的數(shù)據(jù)進行取出
RST:報文當中的RST被設(shè)置為1,表示需要讓對方重新建立連接;雙方在連接未建立好一方發(fā)數(shù)據(jù),另一方要求對方重新建立連接,建立好的連接出現(xiàn)了異常也會要求重新建立連接
1、應(yīng)答機制
- 示圖:
- 概念及介紹:
- 在進行網(wǎng)絡(luò)通信時,一方發(fā)出的數(shù)據(jù)后,它不能保證該數(shù)據(jù)能夠成功被對端收到,因為數(shù)據(jù)在傳輸過程中可能會出現(xiàn)各種各樣的錯誤,只有當收到對端主機發(fā)來的響應(yīng)消息后,該主機才能保證上一次發(fā)送的數(shù)據(jù)被對端成功的收到了,這就叫做真正的可靠,而這種策略在TCP當中就叫做確認應(yīng)答機制
- 在實際的網(wǎng)絡(luò)通信中,最后一次的數(shù)據(jù)傳輸是無法確認對端是否成功收到,但實際沒有必要保證所有消息的可靠性,只要傳輸?shù)暮诵臄?shù)據(jù)都有對應(yīng)的響應(yīng)就可以,一些無關(guān)緊要的數(shù)據(jù)沒有必要保證它的可靠性
注:對端如果沒有收到這個響應(yīng)數(shù)據(jù),會判定上一次發(fā)送的報文丟失了,此時對端可以將上一次發(fā)送的數(shù)據(jù)進行重傳
2、序號機制
- 序號和確認序號:
- TCP將每個字節(jié)的數(shù)據(jù)都進行了編號(TCP具有發(fā)送緩沖區(qū),緩沖區(qū)的下標即為編號),即為序列號
- 每一個ACK都帶有對應(yīng)的確認序列號, 意思是告訴發(fā)送者, 我已經(jīng)收到了哪些數(shù)據(jù); 下一次你從哪里開始發(fā)
- 示圖:
- 序號概念:
- 在雙方實際進行網(wǎng)絡(luò)通信時,為了提高數(shù)據(jù)傳輸?shù)男?,允許一方向另一方連續(xù)發(fā)送多個報文數(shù)據(jù),只要保證發(fā)送的每個報文都有對應(yīng)的響應(yīng)消息就行了
- 在連續(xù)發(fā)送多個報文時,由于各個報文在進行網(wǎng)絡(luò)傳輸時選擇的路徑可能是不一樣的,因此這些報文到達對端主機的先后順序也就可能和發(fā)送報文的順序是不同的,而TCP報頭中的32位序號的作用之一實際就是用來保證報文的有序性的
- 接收端收到多個TCP報文后,就可以根據(jù)TCP報頭當中的32位序列號對這多個報文進行順序重排,重排后將其放到TCP的接收緩沖區(qū)當中,此時接收端這里報文的順序就和發(fā)送端發(fā)送報文的順序是一樣的
- 當進行報文重排時,會根據(jù)當前報文的32位序號與其有效載荷的字節(jié)數(shù),進而確定下一個報文對應(yīng)的序號,通過檢驗序號查看是否有數(shù)據(jù)丟失,進而進行重發(fā)
- 確認序號概念:
- 報頭當中的確認序號實際就是,接收緩沖區(qū)中接收到的最后一個有效數(shù)據(jù)的下一個位置所對應(yīng)的下標
- TCP報頭當中的32位確認序號是告訴對端,當前已經(jīng)收到了之前的哪些數(shù)據(jù),你的數(shù)據(jù)下一次應(yīng)該從哪里開始發(fā)
-
示例:
-
解釋:
當主機B收到主機A發(fā)送過來的32位序號為1的報文時,由于該報文當中包含1000字節(jié)的數(shù)據(jù),因此主機B已經(jīng)收到序列號為1-1000的字節(jié)數(shù)據(jù),于是主機B發(fā)給主機A的響應(yīng)數(shù)據(jù)的報頭當中的32位確認序號的值就會填成1001…
- 為什么要用兩套序號機制:
- 一般來說雙方通信發(fā)送數(shù)據(jù)和應(yīng)答數(shù)據(jù),只用一套序號就可以了;TCP為了保證效率,在應(yīng)答對方之前發(fā)送的數(shù)據(jù)的同時可能想給對方發(fā)送數(shù)據(jù)
- 雙方發(fā)出的報文當中,不僅需要填充32位序號來表明自己當前發(fā)送數(shù)據(jù)的序號,還需要填充32位確認序號,對對方上一次發(fā)送的數(shù)據(jù)進行確認,告訴對方下一次應(yīng)該從哪一字節(jié)序號開始進行發(fā)送
3、超時重傳機制
- 概念及介紹:
- 雙方在進行網(wǎng)絡(luò)通信時,發(fā)送方發(fā)出去的數(shù)據(jù)在一個特定的事件間隔內(nèi)如果得不到對方的應(yīng)答,此時發(fā)送方就會進行數(shù)據(jù)重發(fā),這就是TCP的超時重傳機制
- 超時重傳機制實際就是發(fā)送方在發(fā)送數(shù)據(jù)后開啟了一個定時器,若是在這個時間內(nèi)沒有收到剛才發(fā)送數(shù)據(jù)的確認應(yīng)答報文,則會對該報文進行重傳
- 發(fā)送的數(shù)據(jù)報文丟失:
此時發(fā)送端在一定時間內(nèi)收不到對應(yīng)的響應(yīng)報文,就會進行超時重傳
- 示圖:
說明:主機A發(fā)送數(shù)據(jù)給B之后, 可能因為網(wǎng)絡(luò)擁堵等原因, 數(shù)據(jù)無法到達主機B;如果主機A在一個特定時間間隔內(nèi)沒有收到B發(fā)來的確認應(yīng)答, 就會進行重發(fā)
- 對方的響應(yīng)報文丟失:
此時發(fā)送端也會因為收不到對應(yīng)的響應(yīng)報文,而進行超時重傳
- 示圖:
說明:主機B會收到很多重復(fù)數(shù)據(jù). 那么TCP協(xié)議需要能夠識別出那些包是重復(fù)的包,并且把重復(fù)的丟棄掉,通過序列號就可以很容易做到去重的效果
注:當發(fā)送緩沖區(qū)當中的數(shù)據(jù)被發(fā)送出去后,操作系統(tǒng)不會立即將該數(shù)據(jù)從發(fā)送緩沖區(qū)當中刪除或覆蓋,而會讓其保留在發(fā)送緩沖區(qū)當中,以免需要進行超時重傳,直到收到該數(shù)據(jù)的響應(yīng)報文后,發(fā)送緩沖區(qū)中的這部分數(shù)據(jù)才可以被刪除或覆蓋
- 超時重傳的等待時間:
- 超時重傳的時間設(shè)置的太長,會導(dǎo)致丟包后對方長時間收不到對應(yīng)的數(shù)據(jù),進而影響整體重傳的效率;超時重傳的時間設(shè)置的太短,會導(dǎo)致對方收到大量的重復(fù)報文,可能對方發(fā)送的響應(yīng)報文還在網(wǎng)絡(luò)中傳輸而并沒有丟包,但此時發(fā)送方就開始進行數(shù)據(jù)重傳了,而發(fā)送大量重復(fù)報文會是對網(wǎng)絡(luò)資源的浪費
- 超時重傳的時間需要保證“確認應(yīng)答一定能在這個時間內(nèi)返回”,同時這個時間的長短是與網(wǎng)絡(luò)環(huán)境有關(guān)的,會根據(jù)網(wǎng)絡(luò)狀況進行相應(yīng)的變化
- Linux中(BSD Unix和Windows也是如此),超時以500ms為一個單位進行控制,每次判定超時重發(fā)的超時時間都是500ms的整數(shù)倍,如果重發(fā)一次之后,仍然得不到應(yīng)答,下一次重傳的等待時間就是2 × 500 2\times5002×500ms,如果仍然得不到應(yīng)答,那么下一次重傳的等待時間就是4 × 500 4\times5004×500ms,以此類推以指數(shù)的形式遞增
- 當累計到一定的重傳次數(shù)后,TCP就會認為是網(wǎng)絡(luò)或?qū)Χ酥鳈C出現(xiàn)了異常,進而強轉(zhuǎn)關(guān)閉連接
4、連接管理機制
- 概念及介紹:
- TCP是面向連接的,在進行TCP通信之前需要先建立連接,保證傳輸數(shù)據(jù)的可靠性
- 面向連接是TCP可靠性的一種,一臺機器上可能會存在大量的連接,此時操作系統(tǒng)就需要對這些連接進行管理
- 建立連接,實際就是在操作系統(tǒng)中用該結(jié)構(gòu)體定義一個結(jié)構(gòu)體變量,然后填充連接的各種屬性字段,最后將其插入到管理連接的數(shù)據(jù)結(jié)構(gòu)當中即可;斷開連接,實際就是將某個連接從管理連接的數(shù)據(jù)結(jié)構(gòu)當中刪除,釋放該連接曾經(jīng)占用的各種資源
- 示圖:
- 服務(wù)端狀態(tài)轉(zhuǎn)化:
- [CLOSED -> LISTEN] 服務(wù)器端調(diào)用listen后進入LISTEN狀態(tài), 等待客戶端連接
- [LISTEN -> SYN_RCVD] 一旦監(jiān)聽到連接請求(同步報文段), 就將該連接放入內(nèi)核等待隊列中, 并向客戶端發(fā)送SYN確認報文
- [SYN_RCVD -> ESTABLISHED] 服務(wù)端一旦收到客戶端的確認報文, 就進入ESTABLISHED狀態(tài), 可以進行讀寫數(shù)據(jù)了
- [ESTABLISHED -> CLOSE_WAIT] 當客戶端主動關(guān)閉連接(調(diào)用close), 服務(wù)器會收到結(jié)束報文段, 服務(wù)器返回確認報文段并進入CLOSE_WAIT
- [CLOSE_WAIT -> LAST_ACK] 進入CLOSE_WAIT后說明服務(wù)器準備關(guān)閉連接(需要處理完之前的數(shù)據(jù)); 當服務(wù)器真正調(diào)用close關(guān)閉連接時, 會向客戶端發(fā)送FIN, 此時服務(wù)器進入LAST_ACK狀態(tài), 等待最后一個ACK到來(這個ACK是客戶端確認收到了FIN)
- [LAST_ACK -> CLOSED] 服務(wù)器收到了對FIN的ACK, 徹底關(guān)閉連接
- 客戶端狀態(tài)轉(zhuǎn)化:
- [CLOSED -> SYN_SENT] 客戶端調(diào)用connect, 發(fā)送同步報文段
- [SYN_SENT -> ESTABLISHED] connect調(diào)用成功, 則進入ESTABLISHED狀態(tài), 開始讀寫數(shù)據(jù)
- [ESTABLISHED -> FIN_WAIT_1] 客戶端主動調(diào)用close時, 向服務(wù)器發(fā)送結(jié)束報文段, 同時進入FIN_WAIT_1
- [FIN_WAIT_1 -> FIN_WAIT_2] 客戶端收到服務(wù)器對結(jié)束報文段的確認, 則進入FIN_WAIT_2, 開始等待服務(wù)器的結(jié)束報文段
- [FIN_WAIT_2 -> TIME_WAIT] 客戶端收到服務(wù)器發(fā)來的結(jié)束報文段, 進入TIME_WAIT, 并發(fā)出LAST_ACK
- [TIME_WAIT -> CLOSED] 客戶端要等待一個2MSL(Max Segment Life, 報文最大生存時間)的時間, 才會進入CLOSED狀態(tài)
三次握手
- 示圖:
- 三次握手過程:
- 第一次握手:客戶端向服務(wù)器發(fā)送的報文當中的SYN位被設(shè)置為1,表示請求與服務(wù)器建立連接
- 第二次握手:服務(wù)器收到客戶端發(fā)來的連接請求報文后,緊接著向客戶端發(fā)起連接建立請求并對客戶端發(fā)來的連接請求進行響應(yīng),此時服務(wù)器向客戶端發(fā)送的報文當中的SYN位和ACK位均被設(shè)置為1
- 第三次握手:客戶端收到服務(wù)器發(fā)來的報文后,得知服務(wù)器收到了自己發(fā)送的連接建立請求,并請求和自己建立連接,最后客戶端再向服務(wù)器發(fā)來的報文進行響應(yīng)
- 需要注意的是,客戶端向服務(wù)器發(fā)起的連接建立請求,是請求建立從客戶端到服務(wù)器方向的通信連接,而TCP是全雙工通信,因此服務(wù)器在收到客戶端發(fā)來的連接建立請求后,服務(wù)器也需要向客戶端發(fā)起連接建立請求,請求建立從服務(wù)器到客戶端方法的通信連接
- 為什么是三次握手,不是其他次數(shù):
- 三次握手是驗證雙方通信信道的最小次數(shù)
TCP是全雙工的,連接建立的核心要務(wù)是驗證雙方的通信信道是否是良好的(從服務(wù)端到客戶端,從客戶端到服務(wù)端的信道),而三次握手恰好是驗證雙方通信信道的最小次數(shù)(此時服務(wù)端和客戶端都進行了數(shù)據(jù)的發(fā)送和接收)
- 三次握手能夠保證連接建立時的異常連接掛在客戶端
- 我們知道最后一次的數(shù)據(jù)發(fā)送是無法知道是否成功被對端接收的,也就是說最后一次的握手是存在丟包的風險的。一方發(fā)起最后一次握手前會進行連接的建立,而另一方在接收到最后一次握手時才會進行連接的建立,如果最后一次握手丟包,那么發(fā)起方會存有一個異常的連接
- 而連接的維護是需要時間成本和空間成本的,同時服務(wù)端和客戶端是一個1:n的數(shù)量狀況,如果異常連接的維護是在服務(wù)端的話,當存在大量的異常連接就會影響服務(wù)器的性能;發(fā)起連接請求是客戶端訪問服務(wù)端,當奇數(shù)次握手時異常連接是掛在客戶端的,而不會影響到服務(wù)器
注:建立連接失敗時的異常連接不會一直維護下去。如果服務(wù)器端長時間收不到客戶端發(fā)來的第三次握手,就會將第二次握手進行超時重傳,此時客戶端就會重新發(fā)出第三次握手;或者當客戶端認為連接建立好后向服務(wù)器發(fā)送數(shù)據(jù)時,此時服務(wù)器會發(fā)現(xiàn)沒有和該客戶端建立連接而要求客戶端重新建立連接(設(shè)置RST標志位)
- 上層調(diào)用和連接之間的關(guān)系:
- connect函數(shù)不參與底層的三次握手,connect函數(shù)的作用只是發(fā)起三次握手。當connect函數(shù)返回時,要么是底層已經(jīng)成功完成了三次握手連接建立成功,要么是底層三次握手失敗
- 如果服務(wù)器端與客戶端成功完成了三次握手,此時在服務(wù)器端就會建立一個連接,但這個連接在內(nèi)核的等待隊列當中,服務(wù)器端需要通過調(diào)用accept函數(shù)將這個建立好的連接獲取上來
- 當服務(wù)器端將建立好的連接獲取上來后,上層就可以通過調(diào)用read/recv函數(shù)和write/send函數(shù)進行數(shù)據(jù)交互了
四次揮手
- 示圖:
- 四次揮手過程:
- 第一次揮手:客戶端向服務(wù)器發(fā)送的報文當中的FIN位被設(shè)置為1,表示請求與服務(wù)器斷開連接
- 第二次揮手:服務(wù)器收到客戶端發(fā)來的斷開連接請求后對其進行響應(yīng)
- 第三次揮手:服務(wù)器收到客戶端斷開連接的請求,且已經(jīng)沒有數(shù)據(jù)需要發(fā)送給客戶端的時候,服務(wù)器就會向客戶端發(fā)起斷開連接請求
- 第四次揮手:客戶端收到服務(wù)器發(fā)來的斷開連接請求后對其進行響應(yīng)
- 為什么是四次揮手:
- TCP是全雙工的,建立的連接是雙向的,所以斷開連接需要將服務(wù)端對客戶端的連接以及客戶端對服務(wù)端的連接都給斷開,每兩次揮手對應(yīng)就是關(guān)閉一個方向的通信信道,因此斷開連接時需要進行四次揮手
- 四次揮手當中的第二次和第三次揮手不能合并在一起,第三次握手是服務(wù)器端想要與客戶端斷開連接時發(fā)給客戶端的請求,服務(wù)器不一定會馬上發(fā)起第三次揮手,服務(wù)器可能還有某些數(shù)據(jù)要發(fā)送給客戶端(此時服務(wù)端對客戶端的連接還沒有斷開)
- 上層調(diào)用和斷開連接之間的關(guān)系:
客戶端發(fā)起斷開連接請求,對應(yīng)就是客戶端主動調(diào)用close函數(shù),服務(wù)器發(fā)起斷開連接請求,對應(yīng)就是服務(wù)器主動調(diào)用close函數(shù),一個close對應(yīng)的就是兩次揮手,雙方都要調(diào)用close,因此就是四次揮手
5、理解CLOSE_WAIT狀態(tài)
- 概念及介紹:
- 客戶端調(diào)用了close函數(shù)發(fā)起兩次揮手,服務(wù)器接收后就會進入CLOSE_WAIT狀態(tài),客戶端再接收到服務(wù)端的ACK之后則會進入到FIN_WAIT_2狀態(tài);但服務(wù)端還沒有發(fā)起兩次揮手,只有完成四次揮手后連接才算真正斷開,此時雙方才會釋放對應(yīng)的連接資源
- 如果服務(wù)器接收到兩次揮手后不進行調(diào)用close,那么服務(wù)器端就會存在大量處于CLOSE_WAIT狀態(tài)的連接,而每個連接都會占用服務(wù)器的資源,最終就會導(dǎo)致服務(wù)器可用資源越來越少
注:對于服務(wù)器上出現(xiàn)大量的 CLOSE_WAIT 狀態(tài), 原因就是服務(wù)器沒有正確的關(guān)閉 socket, 導(dǎo)致四次揮手沒有正確完成,這是一個 BUG,只需要加上對應(yīng)的 close 即可解決問題
6、理解TIME_WAIT狀態(tài)
- 概念及介紹:
客戶端主動關(guān)閉連接時,發(fā)送最后一個ACK后,然后會進入TIME_WAIT狀態(tài),再停留2個MSL時間(后有MSL的解釋),進入CLOSED狀態(tài),所以我們可以粗略地理解成在斷開連接后主動斷開連接的那一方就會進入一個等待狀態(tài),過了一定時間后,再真正的關(guān)閉,這所謂的狀態(tài)也就是TIME_WAIT狀態(tài),這其中所說的一定時間也就是2MSL(MSL:最長分節(jié)生命期maximum segment lifetime,這個狀態(tài)會持續(xù)MSL時長的兩倍,所以稱為2MSL)
- TIME_WAIT狀態(tài)產(chǎn)生的原因:
- 可靠地實現(xiàn)TCP全雙工連接的終止
假設(shè)發(fā)起主動關(guān)閉的一方(client)最后發(fā)送的ACK在網(wǎng)絡(luò)中丟失,由于TCP協(xié)議的重傳機制,執(zhí)行被動關(guān)閉的一方(server)將會重發(fā)其FIN,在該FIN到達client之前,client必須維護這條連接狀態(tài),也就說這條TCP連接所對應(yīng)的資源(client方的local_ip,local_port)不能被立即釋放或重新分配,直到另一方重發(fā)的FIN達到之后,client重發(fā)ACK后,經(jīng)過2MSL時間周期沒有再收到另一方的FIN之后,說明被動關(guān)閉的一方(server)成功收到ACK,這樣才能轉(zhuǎn)變成CLOSED狀態(tài),正式斷開雙方建立的連接
如果主動關(guān)閉一方不維護這樣一個TIME_WAIT狀態(tài),那么當被動關(guān)閉一方重發(fā)的FIN到達時,主動關(guān)閉一方的TCP傳輸層會用RST包響應(yīng)對方,這會被對方認為是有錯誤發(fā)生,然而這事實上只是正常的關(guān)閉連接過程,并非異常
- 允許老的重復(fù)分節(jié)在網(wǎng)絡(luò)中消逝
假設(shè)在12.106.32.254的1500端口和206.168.112.219的21端口之間有一個TCP連接。我們關(guān)閉這個連接,過一段時間后在相同的IP地址和端口之間建立另一個連接。后一個連接稱為前一個連接的化身(incarnation),因為它們的IP地址和端口號都相同
TCP必須防止來自某個連接的老的重復(fù)分組在該連接已終止后再現(xiàn),從而被誤解成屬于同一連接的某個新的化身。為做到這一點,TCP將不給處于TIME_WAIT狀態(tài)的連接發(fā)起新的化身。所以TIME_WAIT狀態(tài)的持續(xù)時間是MSL的2倍,這就足以讓某個方向上的分組最多存活MSL秒即被丟棄,另一個方向上的應(yīng)答最多存活MSL秒也被丟棄;此后,就可以用相同的四元組建立一條新連接而不會發(fā)生前后兩次連接數(shù)據(jù)錯亂的情況
注:MSL在RFC1122中規(guī)定為兩分鐘,但是各個操作系統(tǒng)的實現(xiàn)不同,比如在Centos7上默認配置的值是60s,可以通過cat /proc/sys/net/ipv4/tcp_fin_timeout命令來查看MSL的值
- TIME_WAIT的等待時長為什么是兩個MSL:
MSL是TCP報文的最大生存時間,因此TIME_WAIT狀態(tài)持續(xù)存在2MSL的話,就能保證在兩個傳輸方向上的尚未被接收或遲到的報文段都已經(jīng)消失,同時也是在理論上保證最后一個報文可靠到達的時間
7、流量控制
- 概念及介紹:
- 接收端處理數(shù)據(jù)的速度是有限的,如果發(fā)送端發(fā)的太快,導(dǎo)致接收端的緩沖區(qū)被打滿,此時發(fā)送端繼續(xù)發(fā)送數(shù)據(jù),就會造成丟包,進而引起丟包重傳等一系列連鎖反應(yīng),因此接收端可以將自己接收數(shù)據(jù)的能力告知發(fā)送端,讓發(fā)送端控制自己發(fā)送數(shù)據(jù)的速度
- TCP支持根據(jù)接收端的接收數(shù)據(jù)的能力來決定發(fā)送端發(fā)送數(shù)據(jù)的速度,這個機制叫做流量控制(Flow Control)
- 示圖:
- 說明:
- 接收端將自己可以接收的緩沖區(qū)大小放入 TCP 首部中的 “窗口大小” 字段, 通過ACK端通知發(fā)送端;
- 窗口大小字段越大, 說明網(wǎng)絡(luò)的吞吐量越高;
- 接收端一旦發(fā)現(xiàn)自己的緩沖區(qū)快滿了, 就會將窗口大小設(shè)置成一個更小的值通知給發(fā)送端;
- 發(fā)送端接受到這個窗口之后, 就會減慢自己的發(fā)送速度;
- 如果接收端緩沖區(qū)滿了, 就會將窗口置為0; 這時發(fā)送方不再發(fā)送數(shù)據(jù), 但是需要定期發(fā)送一個窗口探測數(shù)據(jù)段, 使接收端把窗口大小告訴發(fā)送端
- 當窗口大小為0時,發(fā)送端獲取何時可以發(fā)送數(shù)據(jù)的方式:
主動詢問:發(fā)送端每隔一段時間向接收端發(fā)送報文,該報文不攜帶有效數(shù)據(jù),只是為了詢問發(fā)送端的窗口大小,直到接收端的接收緩沖區(qū)有空間后發(fā)送端就可以繼續(xù)發(fā)送數(shù)據(jù)了
等待告知:接收端上層將接收緩沖區(qū)當中的數(shù)據(jù)讀走后,接收端向發(fā)送端發(fā)送一個TCP報文,主動將自己的窗口大小告知發(fā)送端
- 16為數(shù)字最大表示65535,那TCP窗口最大就是65535嗎:
理論上確實是這樣的,但實際上TCP報頭當中40字節(jié)的選項字段中包含了一個窗口擴大因子M,實際窗口大小是窗口字段的值左移M位得到的
- 第一次向?qū)Ψ桨l(fā)送數(shù)據(jù)時如何得知對方的窗口大?。?/li>
雙方在進行TCP通信之前需要先進行三次握手建立連接,而雙方在握手時除了驗證雙方通信信道是否通暢以外,還進行了其他信息的交互,其中就包括告知對方自己的接收能力,因此在雙方還沒有正式開始通信之前就已經(jīng)知道了對方接收數(shù)據(jù)能力
8、滑動窗口
- 概念及引入:
- 在穿行的數(shù)據(jù)通行時,對每一個發(fā)送的數(shù)據(jù)段都要給一個ACK確認應(yīng)答,收到ACK后再發(fā)送下一個數(shù)據(jù)段,而這樣性能較差,效率不高,尤其是數(shù)據(jù)往返的時間較長的時候
- 實際在進行TCP通信中,發(fā)送方在根據(jù)對方的接受能力下可以一次向?qū)Ψ桨l(fā)送多條數(shù)據(jù),這樣可以將等待多個響應(yīng)的時間重疊起來,進而提高數(shù)據(jù)通信的效率
- 示圖:
- 滑動窗口介紹:
- 可以將發(fā)送緩沖區(qū)當中的數(shù)據(jù)分為三部分:已經(jīng)發(fā)送并且已經(jīng)收到ACK的數(shù)據(jù),已經(jīng)發(fā)送還但沒有收到ACK的數(shù)據(jù),還沒有發(fā)送的數(shù)據(jù)
- 窗口大小指的是無需等待確認應(yīng)答而可以繼續(xù)發(fā)送數(shù)據(jù)的最大值,滑動窗口存在的最大意義就是可以提高發(fā)送數(shù)據(jù)的效率
- 示圖:
- 說明:
- 窗口大小指的是無需等待確認應(yīng)答而可以繼續(xù)發(fā)送數(shù)據(jù)的最大值,上圖的窗口大小就是4000個字節(jié)(四個段)發(fā)送前四個段的時候,不需要等待任何ACK直接發(fā)送;收到第一個ACK后,滑動窗口向后移動,繼續(xù)發(fā)送第五個段的數(shù)據(jù),依次類推
- 操作系統(tǒng)內(nèi)核為了維護這個滑動窗口,需要開辟發(fā)送緩沖區(qū)來記錄當前還有哪些數(shù)據(jù)沒有應(yīng)答;只有確認應(yīng)答過的數(shù)據(jù)才能從緩沖區(qū)刪掉(保證數(shù)據(jù)傳輸?shù)目煽啃?,如果丟包可以進行超時重傳)
- 窗口越大,則網(wǎng)絡(luò)的吞吐率就越高
注:實際中滑動窗口的大小等于對方窗口大小與自身擁塞窗口大小的較小值,因為發(fā)送數(shù)據(jù)時不僅要考慮對方的接收能力,還要考慮當前網(wǎng)絡(luò)的狀況
- 示圖:
- 滑動窗口的移動:
滑動窗口會根據(jù)接收到的確認應(yīng)答來移動左邊界的位置,根據(jù)對端和網(wǎng)絡(luò)的情況兩者中的最小值計算確定有邊界的位置,所以滑動窗口也會隨之不斷變寬或者變窄
丟包問題
當發(fā)送端一次發(fā)送多個報文數(shù)據(jù)時,此時的丟包情況也可以分為兩種
- 數(shù)據(jù)包已經(jīng)抵達,ACK丟包
示圖:
- 在發(fā)送端連續(xù)發(fā)送多個報文數(shù)據(jù)時,部分ACK丟包并不要緊,此時可以通過后續(xù)的ACK進行確認
- 因為確認序號表示的是改序號之前的數(shù)據(jù)包已經(jīng)成功的接收到了,下一次從改序號開始發(fā)送數(shù)據(jù)
- 數(shù)據(jù)包丟了
- 示圖:
- 當某一段報文段丟失之后,發(fā)送端會一直收到 1001 這樣的ACK,就像是在提醒發(fā)送端 "我想要的是 1001"一樣
- 如果發(fā)送端主機連續(xù)三次收到了同樣一個 “1001” 這樣的應(yīng)答,就會將對應(yīng)的數(shù)據(jù) 1001 - 2000 重新發(fā)送
- 這個時候接收端收到了 1001 之后,再次返回的ACK就是7001了(因為2001 - 7000)接收端其實之前就已經(jīng)收到了,被放到了接收端操作系統(tǒng)內(nèi)核的接收緩沖區(qū)中
注:這種機制被稱為“高速重發(fā)控制”,也叫做“快重傳”
- 快重傳與超時重傳:
- 超時重傳需要通過設(shè)置重傳定時器,在固定的時間后才會進行重傳;快重傳是在接收者接收到一個
亂序的分組
的話,就返回對前一個正確分組的確認應(yīng)答,當瀏覽器連續(xù)收到三個冗余ACK
,就會馬上快速重傳丟失數(shù)據(jù)
,不必等到超時時間再重傳- 超時重傳缺點是太慢了,超時時間的設(shè)置不好把握;快速重傳解決了超時重傳的慢速缺點,但是多發(fā)了好幾個ACK會導(dǎo)致網(wǎng)絡(luò)更加擁塞
9、擁塞控制
- 概念及介紹:
- 雖然TCP有了滑動窗口這個大殺器,能夠高效可靠的發(fā)送大量的數(shù)據(jù),但是如果在剛開始階段就發(fā)送大量的數(shù)據(jù),仍然可能引發(fā)問題
- 因為網(wǎng)絡(luò)上有很多的計算機,可能當前的網(wǎng)絡(luò)狀態(tài)就已經(jīng)比較擁堵,在不清楚當前網(wǎng)絡(luò)狀態(tài)下,貿(mào)然發(fā)送大量的數(shù)據(jù),是很有可能引起雪上加霜的,此時很可能出現(xiàn)大量丟包的狀況
- TCP引入慢啟動機制,先發(fā)少量的數(shù)據(jù)探路,摸清當前的網(wǎng)絡(luò)擁堵狀態(tài),再決定按照多大的速度傳輸數(shù)據(jù)
注:一旦出現(xiàn)大量的丟包,此時TCP就不再推測是雙方接收和發(fā)送數(shù)據(jù)的問題,而判斷是雙方通信信道網(wǎng)絡(luò)出現(xiàn)了擁塞問題
- 示圖:
- 說明:
此處引入一個概念程為擁塞窗口,發(fā)送開始的時候, 定義擁塞窗口大小為1k;每次收到一個ACK應(yīng)答, 擁塞窗口加1k;每次發(fā)送數(shù)據(jù)包的時候, 將擁塞窗口和接收端主機反饋的窗口大小做比較, 取較小的值作為實際發(fā)送的窗口
像上面這樣的擁塞窗口增長速度, 是指數(shù)級別的,“慢啟動” 只是指初使時慢,但是增長速度非??臁榱瞬辉鲩L的那么快,因此不能使擁塞窗口單純的加倍,此處引入一個叫做慢啟動的閾值:當擁塞窗口超過這個閾值的時候, 不再按照指數(shù)方式增長, 而是按照線性方式增長 示圖:
注:當TCP開始啟動的時候, 慢啟動閾值等于窗口最大值;在每次超時重發(fā)的時候, 慢啟動閾值會變成原來的一半, 同時擁塞窗口置回1
- 注意:
- 少量的丟包,我們僅僅是觸發(fā)超時重傳;大量的丟包,我們就認為網(wǎng)絡(luò)擁塞
- 當TCP通信開始后, 網(wǎng)絡(luò)吞吐量會逐漸上升;隨著網(wǎng)絡(luò)發(fā)生擁堵, 吞吐量會立刻下降
- 擁塞控制,歸根結(jié)底是TCP協(xié)議想盡可能快的把數(shù)據(jù)傳輸給對方,但是又要避免給網(wǎng)絡(luò)造成太大壓力的折中方案
- 如何解決網(wǎng)絡(luò)擁塞問題:
網(wǎng)絡(luò)擁塞時影響的不只是一臺主機,而幾乎是該網(wǎng)絡(luò)當中的所有主機,此時所有使用TCP傳輸控制協(xié)議的主機都會執(zhí)行擁塞避免算法;擁塞控制看似只是談?wù)摰囊慌_主機上的通信策略,實際這個策略是所有主機在網(wǎng)絡(luò)崩潰后都會遵守的策略
10、延遲應(yīng)答
- 如果接收數(shù)據(jù)的主機收到數(shù)據(jù)后立即進行ACK應(yīng)答,此時返回的窗口可能比較小:
- 假設(shè)對方接收端緩沖區(qū)剩余空間大小為1M,對方一次收到500K的數(shù)據(jù)后,如果立即進行ACK應(yīng)答,此時返回的窗口就是500K
- 但實際接收端處理數(shù)據(jù)的速度很快,10ms之內(nèi)就將接收緩沖區(qū)中500K的數(shù)據(jù)消費掉了
- 在這種情況下,接收端處理還遠沒有達到自己的極限,即使窗口再放大一些,也能處理過來
- 如果接收端稍微等一會再進行ACK應(yīng)答,比如等待200ms再應(yīng)答,那么這時返回的窗口大小就是1M
- 示圖:
- 注意:
窗口越大,網(wǎng)絡(luò)吞吐量就越大,傳輸效率就越高,延遲應(yīng)答的目標是在保證網(wǎng)絡(luò)不擁塞的情況下盡量提高傳輸效率
- 不是所有的數(shù)據(jù)包都可以延遲應(yīng)答:
- 數(shù)量限制:每個N個包就應(yīng)答一次
- 時間限制:超過最大延遲時間就應(yīng)答一次(這個時間不會導(dǎo)致誤超時重傳)
注:延遲應(yīng)答具體的數(shù)量和超時時間,依操作系統(tǒng)不同也有差異,一般N取2,超時時間取200ms
11、捎帶應(yīng)答
- 概念及介紹:
- 很多情況下, 客戶端服務(wù)器在應(yīng)用層也是 “一發(fā)一收” 的:客戶端給服務(wù)器發(fā)送數(shù)據(jù),服務(wù)器可能也會給客戶端發(fā)送數(shù)據(jù),那么這個時候ACK可以和數(shù)據(jù)一起回給客戶端,此時發(fā)送的這個報文既發(fā)送了數(shù)據(jù),又完成了對收到數(shù)據(jù)的響應(yīng),這就叫做捎帶應(yīng)答
- 捎帶應(yīng)答實際也是發(fā)送數(shù)據(jù)的效率,此時雙方通信時就可以不用再發(fā)送單純的確認報文了
- 示圖:
12、面向字節(jié)流
- 當創(chuàng)建一個TCP的socket時,同時在內(nèi)核中會創(chuàng)建一個發(fā)送緩沖區(qū)和一個接收緩沖區(qū):
- 調(diào)用write時, 數(shù)據(jù)會先寫入發(fā)送緩沖區(qū)中
- 如果發(fā)送的字節(jié)數(shù)太長, 會被拆分成多個TCP的數(shù)據(jù)包發(fā)出
- 如果發(fā)送的字節(jié)數(shù)太短, 就會先在緩沖區(qū)里等待, 等到緩沖區(qū)長度差不多了, 或者其他合適的時機發(fā)送出去
- 接收數(shù)據(jù)的時候, 數(shù)據(jù)也是從網(wǎng)卡驅(qū)動程序到達內(nèi)核的接收緩沖區(qū)
- 然后應(yīng)用程序可以調(diào)用read從接收緩沖區(qū)拿數(shù)據(jù)
- 另一方面, TCP的一個連接, 既有發(fā)送緩沖區(qū), 也有接收緩沖區(qū), 那么對于這一個連接, 既可以讀數(shù)據(jù), 也可以寫數(shù)據(jù),這個概念叫做全雙工
- 由于緩沖區(qū)的存在,TCP程序的讀和寫不需要一一匹配,例如:
- 寫100個字節(jié)數(shù)據(jù)時,可以調(diào)用一次write寫100字節(jié),也可以調(diào)用100次write,每次寫一個字節(jié)
- 讀100個字節(jié)數(shù)據(jù)時,也完全不需要考慮寫的時候是怎么寫的,既可以一次read100個字節(jié),也可以一次read一個字節(jié),重復(fù)100次
注:在TCP看來這些只是一個個的字節(jié)數(shù)據(jù),它的任務(wù)就是將這些數(shù)據(jù)準確無誤的發(fā)送到對方的接收緩沖區(qū)當中就行了,而至于如何解釋這些數(shù)據(jù)完全由上層應(yīng)用來決定,這就叫做面向字節(jié)流
13、粘包問題
- 概念及解釋:
首先要明確,粘包問題中的 “包” ,是指的應(yīng)用層的數(shù)據(jù)包,在TCP的協(xié)議頭中,沒有如同UDP一樣的 “報文長度” 這樣的字段,但是有一個序號這樣的字段,站在傳輸層的角度,TCP是一個一個報文過來的,按照序號排好序放在緩沖區(qū)中;站在應(yīng)用層的角度,看到的只是一串連續(xù)的字節(jié)數(shù)據(jù),那么應(yīng)用程序看到了這么一連串的字節(jié)數(shù)據(jù),就不知道從哪個部分開始到哪個部分,是一個完整的應(yīng)用層數(shù)據(jù)包文章來源:http://www.zghlxwxcb.cn/news/detail-734078.html
- 要解決粘包問題,本質(zhì)就是要明確報文和報文之間的邊界:
- 對于定長的包,保證每次都按固定大小讀取即可
- 對于變長的包,可以在報頭的位置,約定一個包總長度的字段,從而就知道了包的結(jié)束位置。比如HTTP報頭當中就包含Content-Length屬性,表示正文的長度
- 對于變長的包,還可以在包和包之間使用明確的分隔符。因為應(yīng)用層協(xié)議是程序員自己來定的,只要保證分隔符不和正文沖突即可
- UDP是否存在粘包問題:
- 對于UDP,如果還沒有上層交付數(shù)據(jù),UDP的報文長度仍然在,同時UDP是一個一個把數(shù)據(jù)交付給應(yīng)用層的,有很明確的數(shù)據(jù)邊界,站在應(yīng)用層的角度,使用UDP的時候,要么收到完整的UDP報文,要么不收,不會出現(xiàn)“半個”的情況
- 因此UDP是不存在粘包問題的,根本原因就是UDP報頭當中的16位UDP長度記錄的UDP報文的長度,因此UDP在底層的時候就把報文和報文之間的邊界明確了,而TCP存在粘包問題就是因為TCP是面向字節(jié)流的,TCP報文之間沒有明確的邊界
14、TCP異常情況
- 進程終止:進程終止會釋放文件描述符,仍然可以發(fā)送FIN,和正常關(guān)閉沒有什么區(qū)別
- 機器重啟:和進程終止的情況相同
- 機器掉電/網(wǎng)線斷開:接收端認為連接還在,一旦接收端有寫入操作,接收端發(fā)現(xiàn)連接已經(jīng)不在了,就會進行reset,即使沒有寫入操作,TCP自己也內(nèi)置了一個?;疃〞r器,會定期詢問對方是否還在,如果對方不在會把連接釋放;另外, 應(yīng)用層的某些協(xié)議, 也有一些這樣的檢測機制. 例如HTTP長連接中, 也會定期檢測對方的狀態(tài). 例如QQ, 在QQ斷線之后, 也會定期嘗試重新連接
的分隔符。因為應(yīng)用層協(xié)議是程序員自己來定的,只要保證分隔符不和正文沖突即可文章來源地址http://www.zghlxwxcb.cn/news/detail-734078.html
- UDP是否存在粘包問題:
- 對于UDP,如果還沒有上層交付數(shù)據(jù),UDP的報文長度仍然在,同時UDP是一個一個把數(shù)據(jù)交付給應(yīng)用層的,有很明確的數(shù)據(jù)邊界,站在應(yīng)用層的角度,使用UDP的時候,要么收到完整的UDP報文,要么不收,不會出現(xiàn)“半個”的情況
- 因此UDP是不存在粘包問題的,根本原因就是UDP報頭當中的16位UDP長度記錄的UDP報文的長度,因此UDP在底層的時候就把報文和報文之間的邊界明確了,而TCP存在粘包問題就是因為TCP是面向字節(jié)流的,TCP報文之間沒有明確的邊界
14、TCP異常情況
- 進程終止:進程終止會釋放文件描述符,仍然可以發(fā)送FIN,和正常關(guān)閉沒有什么區(qū)別
- 機器重啟:和進程終止的情況相同
- 機器掉電/網(wǎng)線斷開:接收端認為連接還在,一旦接收端有寫入操作,接收端發(fā)現(xiàn)連接已經(jīng)不在了,就會進行reset,即使沒有寫入操作,TCP自己也內(nèi)置了一個?;疃〞r器,會定期詢問對方是否還在,如果對方不在會把連接釋放;另外, 應(yīng)用層的某些協(xié)議, 也有一些這樣的檢測機制. 例如HTTP長連接中, 也會定期檢測對方的狀態(tài). 例如QQ, 在QQ斷線之后, 也會定期嘗試重新連接
到了這里,關(guān)于Linux網(wǎng)絡(luò)-UDP/TCP協(xié)議詳解的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!