计算机网络 | 传输层 :UDP与TCP协议详解
傳輸層
- UDP
- UDP的協(xié)議格式
- UDP的特點
- 基于UDP的應用層知名協(xié)議
- UDP如何實現(xiàn)可靠傳輸
- TCP
- TCP的協(xié)議格式
- TCP的特點
- 連接管理機制
- 三次握手
- 四次揮手
- 保活機制
- 問題補充
- 可靠傳輸
- 確認應答
- 超時重傳
- 避免丟包重傳
- 滑動窗口
- 停止等待協(xié)議
- 回退N步協(xié)議
- 選擇重傳協(xié)議
- 流量控制
- 擁塞控制
- 挽救傳輸性能
- 快速重傳
- 延遲應答
- 捎帶應答
- 面向字節(jié)流
- 基于TCP的應用層知名協(xié)議
傳輸層是整個網(wǎng)絡(luò)體系結(jié)構(gòu)中的關(guān)鍵層次之一,主要負責兩個主機中進程之間的數(shù)據(jù)傳輸。
在傳輸層中常見的協(xié)議就是TCP協(xié)議(傳輸控制協(xié)議),UDP協(xié)議(用戶數(shù)據(jù)報協(xié)議)
UDP
UDP協(xié)議,即用戶數(shù)據(jù)報協(xié)議
UDP的協(xié)議格式
- 16位源端端口/目的端口:表示源端/對端的端口號,源端端口有時候可以不設(shè)置(不關(guān)心通信的端口),可以設(shè)置為0。
- 16位數(shù)據(jù)報長度:標志UDP首部與發(fā)送數(shù)據(jù)的長度之和,大小為2^16,即64K,65535。
- 16位校驗和:用于檢驗接收的數(shù)據(jù)與發(fā)送的數(shù)據(jù)是否一致,不一致則丟棄。校驗方法:二進制反碼求和,即對報文從頭開始的每個字節(jié)進行取反相加,高出16位則截斷高位,與低16位相加,得到校驗和。
UDP的特點
其主要特點為:無連接,不可靠,面向數(shù)據(jù)報。
- 無連接
即不需要建立連接也可以發(fā)送數(shù)據(jù)。只需要知道對端的端口號和ip地址就可以直接傳輸。就比如寄快遞,只需要知道人家的地址就可以送過去,不需要與別人提前建立聯(lián)系 - 不可靠
即不能保證數(shù)據(jù)安全有序的到達對端。因為UDP不存在重傳機制與確認機制,所以并不能保證數(shù)據(jù)能夠到達對端,可能會在途中出現(xiàn)丟包,即使丟包了也不會報錯和重傳。UDP的報頭中不存在序號,并且是無連接的,所以他沒法保證數(shù)據(jù)到達后的順序,需要我們自己在應用層進行包序管理。 - 面向數(shù)據(jù)報
即不能靈活的控制讀寫次數(shù)與數(shù)據(jù)的長度,是一種限制了傳輸數(shù)據(jù)大小的傳輸方式。并且UDP的數(shù)據(jù)傳輸是整條的,不會拆分和合并數(shù)據(jù)。
面向數(shù)據(jù)報:
數(shù)據(jù)報長度字段只有16位,報頭要占8個字節(jié),所以數(shù)據(jù)報的長度不能大于(64K- 8) 。
UDP給應用層傳下來的報文添加首部后就會直接轉(zhuǎn)交給網(wǎng)絡(luò)層,所以對于較大的數(shù)據(jù),需要我們自己在應用層進行分包和包序管理進行多次發(fā)送。
UDP在報頭中定義了數(shù)據(jù)長度,所以傳輸?shù)臅r候都是整條收發(fā)。
所以接收時緩沖區(qū)必須要足夠大,如果緩沖區(qū)大于或者小于一條數(shù)據(jù)的大小時都會接收失敗,因為UDP不會交付半條或者多條數(shù)據(jù)。
基于UDP的應用層知名協(xié)議
- NFS: 網(wǎng)絡(luò)文件系統(tǒng)
- TFTP: 簡單文件傳輸協(xié)議
- DHCP: 動態(tài)主機配置協(xié)議
- BOOTP: 啟動協(xié)議(用于無盤設(shè)備啟動)
- DNS: 域名解析協(xié)議
UDP如何實現(xiàn)可靠傳輸
如果光光依靠UDP本身是無法實現(xiàn)可靠傳輸?shù)?#xff0c;因為其無法保證數(shù)據(jù)有序且到達,所以可以參考TCP的可靠性機制,在應用層也為其引入類似邏輯
例如
TCP
TCP協(xié)議,即傳輸控制協(xié)議
TCP的協(xié)議格式
- 16位源端端口/目的端口:表示源端/對端的端口號,源端端口有時候可以不設(shè)置(不關(guān)心通信的端口),可以設(shè)置為0。
- 32位序號:序號是指發(fā)送數(shù)據(jù)的位置。每發(fā)送一次數(shù)據(jù),就累加一次該數(shù)據(jù)字節(jié)數(shù)的大小。序號不會從0或1開始,而是在建立連接時由計算機生成的隨機數(shù)作為其初始值,通過SYN包傳給接收端主機。
- 32位確認序號:確認序號是指下一次應該收到的數(shù)據(jù)的序列號。實際上,它是指已收到確認序號減一為止的數(shù)據(jù)。發(fā)送端接收到這個確認序號以后可以認為在這個序號以前的數(shù)據(jù)都已經(jīng)被正常接收。
TCP通過序號和確認序號來實現(xiàn)包序管理,確保TCP數(shù)據(jù)是有序交付的。 - 4位數(shù)據(jù)偏移(首部長度):表示TCP首部的長度,單位為4字節(jié)即32位,因為數(shù)據(jù)偏移具有4位,所能表示的最大數(shù)據(jù)為15即2^4 - 1,所以TCP首部的最大長度為15 * 4 = 60字節(jié),因為數(shù)據(jù)偏移最少為5(除選項),所以TCP首部的最小長度為20字節(jié)。
- 6位保留位:保留為今后使用,一般設(shè)置為 0。
- 6位標志位:有六種標志位,用來描述本報文的性質(zhì)
URG(Urgent Flag):該為為1時,表示包中有需要緊急處理的數(shù)據(jù)。對于需要緊急處理的數(shù)據(jù),會在后面的緊急指針中再進行解釋。
ACK(Acknowledge Flag):該位為1時,確認應答的字段變?yōu)橛行?/strong>。TCP規(guī)則除了最初建立時的SYN包之外該為必須設(shè)置為1。
PSH(Push Flag):該位為1時,表示需要將受到的數(shù)據(jù)立即傳輸給上層的應用。PSH為0時,則不需要立即上層而是先進行緩存。
RST(ResetFlag):該位為1時表示TCP連接中出現(xiàn)異常必須強制斷開連接。例如,一個沒有被使用的端口即使發(fā)來連接請求,也無法通行。此時就可以返回一個RST設(shè)置為1的包。此外,程序宕掉或切斷電源等原因?qū)е轮鳈C重啟的情況下,由于所有的連接信息將全部被初始化,所以原有的TCP通行也將不能繼續(xù)進行。這種情況下,如果通信對方發(fā)送一個設(shè)置為1的RST包,就會使用心強制斷開連接。
SYN(Synchronize Flag): 用于建立連接。SYN為1表示希望建立連接,并在其序列號的字段進行序列號初始值的設(shè)定。
FIN(Finish Flag):該位為1時,表示今后不會再有數(shù)據(jù)發(fā)送,希望斷開連接。當通信結(jié)束希望斷開連接時,通信雙方的主機之間就可以相互交換FIN位置為1的TCP段。每個主機又對對方的FIN包進行確認應答以后就可以斷開連接。不過,主機收到FIN設(shè)置為1的TCP端以后不必馬上回復一個FIN包,而是可以等到緩沖區(qū)中所有數(shù)據(jù)都已成功發(fā)送而被自動刪除之后再發(fā)。
- 16位窗口大小:指定滑動窗口的大小,即從TCP首部的確認序號所指位置開始能夠接收的數(shù)據(jù)大小,TCP不允許發(fā)送超過此處所示大小的數(shù)據(jù)。用于實現(xiàn)滑動窗口機制,來進行流量控制
- 16位校驗和:用于檢驗接收的數(shù)據(jù)與發(fā)送的數(shù)據(jù)是否一致,不一致則丟棄。校驗方法:二進制反碼求和,即對報文從頭開始的每個字節(jié)進行取反相加,高出16位則截斷高位,與低16位相加,得到校驗和。
- 16位緊急指針: 標識哪部分數(shù)據(jù)是緊急數(shù)據(jù)(帶外數(shù)據(jù)),這段數(shù)據(jù)的優(yōu)先級更高,會提前傳送
- 0-40字節(jié)選項:選項字段用于提高TCP的傳輸性能,主要協(xié)商和描述一些信息。因為TCP首部大小最高為60字節(jié),而前面必須的有20字節(jié),所以選項的大小可以為0-40字節(jié)。
- 填充位:保證TCP首部大小為4字節(jié)的整數(shù)倍,不夠則填充
TCP的特點
其主要特點為:面向連接,可靠,面向字節(jié)流。
- 面向連接:通信必須在建立連接之后,通過連接管理機制實現(xiàn)。
- 可靠傳輸:保證數(shù)據(jù)安全有序的到達對端
- 面向字節(jié)流:以字節(jié)流的方式傳輸
連接管理機制
TCP通過首部的標志位來實現(xiàn)連接的管理,完成通信。
通常情況下,需要經(jīng)過三次握手來建立連接,四次揮手來斷開連接
這里我簡單的畫了一個圖
三次握手
開始時,客戶端處于CLOSED狀態(tài),服務端處于CLOSED狀態(tài)。
之后服務端進入LISTEN狀態(tài),開始監(jiān)聽(只有處于監(jiān)聽狀態(tài)才會處理連接)。
第一次握手(客戶端向服務端揮手):客戶端向服務端發(fā)送一個SYN請求建立連接,客戶端轉(zhuǎn)為SYN_SENT狀態(tài)。
第二次握手(服務端向客戶端揮手):服務端一旦監(jiān)聽到連接請求,就會轉(zhuǎn)為SYN_RECV狀態(tài),并且向客戶端發(fā)送一個SYN和ACK來告訴客戶端我已經(jīng)收到了你的SYN連接請求,并且也發(fā)起連接。
第三次握手(客戶端向服務端揮手):客戶端收到后轉(zhuǎn)為ESTABLISHED狀態(tài)。并且向服務端發(fā)送一個ACK給服務端,告知服務端我也收到了你的SYN請求,服務端收到后也進入ESTABLISHED狀態(tài)。
簡單點來說:
第一次握手:客戶端:在嗎,我是XX,你聽到我說話了嗎?
第二次握手:服務端:我聽到你說話了,你聽到我說話了嗎?
第三次握手:客戶端:我也聽到你說話了,既然我們互相都能聽到,就開始通信吧。
四次揮手
第一次揮手(客戶端向服務端揮手):客戶端向服務端發(fā)送一個FIN請求斷開連接,客戶端處于FIN_WAIT_1狀態(tài)。發(fā)送FIN表示發(fā)送端不再發(fā)送數(shù)據(jù),但不代表不接收數(shù)據(jù)。
第二次揮手(服務端向客戶端揮手):服務端向哭護短回復一個ACK確認收到了FIN。并且轉(zhuǎn)為CLOSE_WAIT狀態(tài)(此時服務端已經(jīng)不再接受數(shù)據(jù)(關(guān)閉讀操作),但是還會繼續(xù)發(fā)送,所以此時會等待上層程序處理)
第三次揮手(服務端向客戶端揮手):此時服務端也完成了寫操作,所以向服務端發(fā)送一個FIN請求斷開連接,并且進入LASK_ACK狀態(tài)。
第四次揮手(客戶端向服務端揮手):客戶端收到了服務端的FIN,并且向服務端回復一個ACK表示已經(jīng)收到。同時客戶端進入TIME_WAIT狀態(tài)。服務端收到ACK后斷開連接進入CLOSED狀態(tài),客戶端也進入CLOSED狀態(tài)。
簡單來說
第一次揮手:客戶端:我要說的話已經(jīng)說完了。
第二次揮手:服務端:你要說的我都聽到了,但是我的話還沒說完。
第三次揮手:服務端:我要說的話也說完了。
第四次揮手:客戶端:既然我們都說完了,那就結(jié)束通話吧。
?;顧C制
在TCP通信中,如果兩端長時間沒有數(shù)據(jù)往來(默認7200秒),則每隔一段時間(默認75秒),服務端就會向客戶端發(fā)送一個?;钐綔y數(shù)據(jù)報,讓客戶端進行回復,如果多次(默認9次)沒有收到響應,則代表連接已經(jīng)斷開。
通過?;顧C制來確保如果有一端斷開,能夠及時處理。
問題補充
TCP握手為什么三次,能不能兩次或者四次
兩次不安全,四次沒必要。SYN的目的是為了確認對方是否具有收發(fā)數(shù)據(jù)的能力,并且得到ACK回復后,則證明對方收到數(shù)據(jù)并且當前在線。如果要建立連接,就必須確保雙方都具有收發(fā)數(shù)據(jù)的能力并且當前處于在線狀態(tài)。
為什么不能兩次?
如果只有兩次就能建立連接,那就代表著客戶端發(fā)起SYN連接,服務端確認后回復ACK+SYN就直接建立連接。
1.如果客戶端連續(xù)發(fā)送多次請求,服務端就會建立多次連接,嚴重的浪費資源。
2.如果客戶端發(fā)起SYN請求后就斷開,或者是因為延遲很久才發(fā)到,等服務端收到時客戶端已經(jīng)斷開連接,這時這個連接是失敗的,但是服務端還是創(chuàng)建了一個毫無意義的套接字,嚴重浪費了資源。
為什么不用四次?
四次握手完全沒有必要,建立連接的SYN和確認回復的ACK報文是可以一起發(fā)送的,沒有必要分開來增加操作。
TCP揮手為什么要四次,三次可以嗎?
不行,發(fā)送FIN包只能代表著主動關(guān)閉方不再發(fā)送數(shù)據(jù),但不代表著不再接受數(shù)據(jù),所以被動關(guān)閉方在回復ACK后還是有可能繼續(xù)發(fā)送數(shù)據(jù),等到被動關(guān)閉方所有數(shù)據(jù)發(fā)送完后才會發(fā)送FIN,主動關(guān)閉方收到后回復ACK才會斷開連接。這也就是為什么建立連接時ACK可以和SYN一起發(fā)送,而斷開連接時FIN不能和ACK一起發(fā)送的原因。(如果被動關(guān)閉方不需要發(fā)送數(shù)據(jù),則此時可以三次揮手)
TCP三次握手失敗時,服務端如何處理?
1.如果服務端沒有收到SYN,則什么都不做(因為壓根沒有建立起來連接,出現(xiàn)情況可能是SYN丟失)
2.服務端發(fā)送了SYN和ACK后,沒有收到客戶端的ACK,此時則說明客戶端可能不在線,此時發(fā)送一個RST重置連接,并且釋放已有資源。
TIME_WAIT有什么用?
在TIME_WAIT狀態(tài)時,主動關(guān)閉方?jīng)]有直接調(diào)用close釋放資源,而是等到確保被動關(guān)閉方收到ACK確認后調(diào)用close,主動關(guān)閉方才調(diào)用。
如果沒有TIME_WAIT,主動關(guān)閉方直接再發(fā)送完ACK后斷開連接,就會有如下幾種情況。
- 被動關(guān)閉方?jīng)]有close釋放資源,則新啟用的客戶端就有可能會出現(xiàn)和原來的客戶端具有一樣的地址信息。
- 主動關(guān)閉方發(fā)送的ACK丟失,被動關(guān)閉方?jīng)]有收到這個ACK,就會卡在LACK_ACK狀態(tài),所以超時后被動關(guān)閉方會重傳一個FIN。
這時就會有兩種情況
1.剛啟用的新客戶端綁定地址信息成功,但是此時卻收到了被動關(guān)閉方重傳的FIN,對新連接產(chǎn)生影響。
2.如果新啟用的客戶端向服務端發(fā)送SYN連接,但是此時服務端處于LACK_ACK狀態(tài),此時他需要的是ACK而不是SYN,所以他會發(fā)送一個RST來重置連接。
所以為了避免上述幾種情況,就添加了TIME_WAIT,等待一段時間確保被動關(guān)閉方收到ACK,即使沒有收到,也留有了足夠的時間來給被動關(guān)閉方進行FIN的重傳。
等待的時間:默認為兩個MSL時間(報文最大生存時間)
一臺主機上出現(xiàn)大量的TIME_WAIT是什么原因?如何處理?
TIME_WAIT狀態(tài)是出現(xiàn)在主動關(guān)閉方的,如果出現(xiàn)大量的TIME_WAIT,就說明有大量的連接被主動關(guān)閉,可能是惡意攻擊或者爬蟲等。處理方法,調(diào)整TIME_WAIT的等待時間或者開啟地址重用(運行新的套接字使用已綁定的地址端口,因為TIME_WAIT中的套接字無法綁定,啟用后就可以直接頂替掉原來的)。
一臺主機上出現(xiàn)大量的CLOSE_WAIT是什么原因?如何處理?
CLOSE_WAIT狀態(tài)是在被動關(guān)閉方收到主動關(guān)閉方的FIN后進入的,此時主動關(guān)閉方已經(jīng)不再發(fā)送數(shù)據(jù),所以此時被動關(guān)閉方的讀端已經(jīng)被關(guān)閉,但是被動關(guān)閉方還需要等到他所有的數(shù)據(jù)發(fā)送完才會結(jié)束,所以此時被動關(guān)閉方會等待上層應用進行處理,處理結(jié)束后才會發(fā)送FIN。而如果出現(xiàn)大量的CLOSE_WAIT,則說明被動關(guān)閉方的上層應用處理有問題,沒有正確的關(guān)閉SOCKET釋放資源,所以此時就不會發(fā)送FIN,導致一直卡在CLOSE_WAIT。
可靠傳輸
TCP與UDP不一樣,他能夠確保數(shù)據(jù)安全有序的到達對端。
通過以下方式
確認應答
TCP在首部中給每一個發(fā)送的數(shù)據(jù)都設(shè)置了序號和確認序號。
通過序號和確認序號,發(fā)送方告訴了接收方我發(fā)送的數(shù)據(jù)的序號,以及數(shù)據(jù)的長度。而接收方則回復發(fā)送方,我已經(jīng)收到了哪些數(shù)據(jù),你下一次應該從哪一個位置開始發(fā)送。
seq:本條數(shù)據(jù)的起始序號。為上一條數(shù)據(jù)的ack
ack:對對方發(fā)送數(shù)據(jù)的確認序號,告訴對方這個位置之前的所有數(shù)據(jù)已收到。確認序號為本條數(shù)據(jù)的起始序號加上數(shù)據(jù)長度。也就是上一條的seq + len
len:本條數(shù)據(jù)的長度。
這里簡單的畫個圖
如果在傳輸過程中,前面的某一個數(shù)據(jù)丟失,即使這里的1025-2048和2049-3072已經(jīng)到達,但是這些數(shù)據(jù)的依舊無法確認回復,因為確認回復必須要保證確認序號ack前的所有數(shù)據(jù)都要到達。這么做的目的是為了防止因為確認回復的丟失導致的重傳。
即使是因為丟包或者延遲而導致前面的數(shù)據(jù)晚到或重傳,等到接收到重傳的數(shù)據(jù)后,再一個個對之前發(fā)送的數(shù)據(jù)進行確認應答,并通過序號在接受緩沖區(qū)中進行排序。
超時重傳
在通信時,某一主機在給另一個主機發(fā)送數(shù)據(jù)后,可能會因為延遲或者丟包等網(wǎng)絡(luò)原因,導致數(shù)據(jù)不能到達,為了確保數(shù)據(jù)能夠到達對端,TCP加入了超時重傳機制,當發(fā)送端在特定的時間內(nèi)沒有收到來自接收端的確認應答時,就會重新發(fā)送,
同時,不僅發(fā)送的數(shù)據(jù)會丟失,確認應答也有可能丟失,這時也會重傳。
這個時間間隔也需要合理設(shè)置
最理想的情況下, 找到一個最小的時間, 保證 “確認應答一定能在這個時間內(nèi)返回”.
但是這個時間的長短, 隨著網(wǎng)絡(luò)環(huán)境的不同, 是有差異的
如果超時時間設(shè)的太長, 會影響整體的重傳效率;
如果超時時間設(shè)的太短, 有可能會頻繁發(fā)送重復的包
TCP為了保證無論在任何環(huán)境下都能比較高性能的通信, 因此會動態(tài)計算這個最大超時時間
Linux中(BSD Unix和Windows也是如此), 超時以500ms為一個單位進行控制, 每次判定超時重發(fā)的超時
時間都是500ms的整數(shù)倍.
如果重發(fā)一次之后, 仍然得不到應答, 等待 2500ms 后再進行重傳
如果仍然得不到應答, 等待4500ms 進行重傳. 依次類推, 以指數(shù)形式遞增
累計到一定的重傳次數(shù), TCP認為網(wǎng)絡(luò)或者對端主機出現(xiàn)異常,強制關(guān)閉連接
避免丟包重傳
滑動窗口
從前面的確認應答機制可以看到,如果對于每一個數(shù)據(jù),發(fā)送后等需要等到接受其回復確認,才發(fā)送下一個數(shù)據(jù),就會導致效率的低下,尤其是網(wǎng)絡(luò)較差時,數(shù)據(jù)的往返之間過長的情況。
既然這樣一收一發(fā)的效率過慢,那么一次性發(fā)送多條,就可以解決這種問題,但是如果發(fā)送的數(shù)量過多,就可能會導致緩沖區(qū)滿而出現(xiàn)丟包,為了控制發(fā)送數(shù)據(jù)的規(guī)模,于是TCP就引入了滑動窗口機制。
在TCP首部中我們看到有一個窗口大小的字段,那個就是滑動窗口的大小,其限制了發(fā)送方最多發(fā)送多少數(shù)據(jù)。同時還有MSS(最大數(shù)據(jù)段大小,選取兩邊最小的一個MSS作為最大數(shù)據(jù)段大小),在三次握手的時候雙方進行協(xié)商,規(guī)定好通信時的MSS和窗口大小。
窗口大小不能大于接收方的接受緩沖區(qū)中剩余空間大小,否則多出來的數(shù)據(jù)會直接丟棄,導致丟包。
發(fā)送端維護發(fā)送窗口:用于限制一次能夠發(fā)送的數(shù)據(jù)
后沿:數(shù)據(jù)發(fā)送的起始位置,等待確認回復的數(shù)據(jù),如果得到了回復,則后沿移動。
前沿:數(shù)據(jù)發(fā)送的結(jié)束位置,前沿減去后沿必須小于等于窗口大小,移動取決于窗口大小。
例如這張圖,窗口大小為4000,當1001-2001的數(shù)據(jù)得到回復后,窗口前沿后沿都向后移動1000.
接收端維護接受窗口:用于進行數(shù)據(jù)的排序。
后沿:數(shù)據(jù)接受的起始位置,移動取決于是否收到后沿數(shù)據(jù)。
前沿:接收緩沖區(qū)剩余空間大小加上后沿,移動取決于接收緩沖區(qū)剩余大小。
滑動窗口機制允許發(fā)送端根據(jù)窗口大小和mss連續(xù)發(fā)送多條數(shù)據(jù),并且為丟包的情況,也做好了準備。
其又引入了下面三個協(xié)議。
停止等待協(xié)議
停止等待協(xié)議就是得到一條回復,才發(fā)送下一條數(shù)據(jù)。
如圖
回退N步協(xié)議
一條數(shù)據(jù)丟失了,則需要發(fā)送端將這條數(shù)據(jù)以后的數(shù)據(jù)全部重傳
選擇重傳協(xié)議
如果一條協(xié)議丟失了,就僅僅對丟失的數(shù)據(jù)進行重傳
流量控制
接收端處理數(shù)據(jù)的速度是有限的. 如果發(fā)送端發(fā)的太快, 導致接收端的緩沖區(qū)被打滿, 這個時候如果發(fā)送端繼續(xù)發(fā)送,
就會造成丟包, 繼而引起丟包重傳等等一系列連鎖反應.
因此TCP支持根據(jù)接收端的處理能力, 來決定發(fā)送端的發(fā)送速度。這個機制就叫做流量控制
- 接收端將自己可以接收的緩沖區(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ā)送端
擁塞控制
雖然滑動窗口能夠高效的發(fā)送大量的數(shù)據(jù),但是在開始階段就發(fā)送大量的數(shù)據(jù),也可能會出現(xiàn)問題。 假設(shè)此時網(wǎng)絡(luò)狀態(tài)不是很好,可能有很多主機在使用,導致網(wǎng)絡(luò)的擁擠,在不了解網(wǎng)絡(luò)狀態(tài)的情況下貿(mào)然發(fā)送大量的數(shù)據(jù),可能就會導致發(fā)送的數(shù)據(jù)越多,丟包也就越多。
所以TCP又引入了一個擁塞控制的機制來解決這個問題。
擁塞控制:以一種慢啟動,快增長的傳輸方式,進行根據(jù)網(wǎng)絡(luò)狀態(tài)調(diào)整發(fā)送速度的機制
先發(fā)少量的數(shù)據(jù),搞清楚當前的網(wǎng)絡(luò)狀況,再根據(jù)網(wǎng)絡(luò)的狀態(tài)來調(diào)整速度,如果網(wǎng)絡(luò)狀態(tài)正常,則快速的增加發(fā)送的速度。
此處引入一個概念程為擁塞窗口
發(fā)送開始的時候, 定義擁塞窗口大小為1;
每次收到一個ACK應答, 擁塞窗口加1;
每次發(fā)送數(shù)據(jù)包的時候, 將擁塞窗口和接收端主機反饋的窗口大小做比較, 取較小的值作為實際發(fā)送的窗口
少量的丟包, 我們僅僅是觸發(fā)超時重傳; 大量的丟包, 我們就認為網(wǎng)絡(luò)擁塞;
當TCP通信開始后, 網(wǎng)絡(luò)吞吐量會逐漸上升; 隨著網(wǎng)絡(luò)發(fā)生擁堵, 吞吐量會立刻下降;
慢開始:設(shè)置擁塞窗口大小為1,之后每次收到一個確認回復ACK,就將擁塞窗口的大小*2。當達到慢開始的門限值時,就會使用擁塞避免算法。慢開始的作用主要是不了解當前的網(wǎng)絡(luò)狀況,為了避免因為快速增長而導致的大量丟包情況。
擁塞避免:當達到慢開始門限值的時候,就會啟用加法增大算法,即每次收到一個確認回復ACK,就讓窗口大小+1。當出現(xiàn)網(wǎng)絡(luò)擁塞的情況時(丟包、超時),令擁塞窗口的門限值等于當前擁塞窗口大小的一半(即乘法減小),接著將當前窗口大小設(shè)置為1,重新進入慢開始。
快重傳:當連續(xù)收到三次重復確認應答時,他此時就會對確認序號ack位置的數(shù)據(jù)進行重傳,因為發(fā)送三次確認回復的時間比起等待超時要少了很多,所以這種機制也被稱為快速重傳機制。
快恢復:當出現(xiàn)了快重傳的情況時,就說明當前網(wǎng)絡(luò)狀況存在問題,但是又由于我們能夠連續(xù)三次收到確認應答,就說明了當前的問題并不是很嚴重,沒有必要重新進行慢開始。所以當前會將擁塞窗口的門限值設(shè)置為當前窗口大小的一般,并直接將窗口大小設(shè)置為門限值,直接開始擁塞避免。由于跳過了慢開始階段直接進行擁塞避免,因此被稱為快恢復
擁塞控制,歸根結(jié)底就是TCP想盡可能快的傳送數(shù)據(jù),但是又怕給網(wǎng)絡(luò)造成巨大的壓力,所以采取這種當網(wǎng)絡(luò)狀態(tài)好是吞吐量上升,網(wǎng)絡(luò)狀態(tài)不好時吞吐量下降的折中方法。
挽救傳輸性能
快速重傳
如下圖,當某一個報文段丟失時,接收端會一直回復后沿數(shù)據(jù)的確認應答,提示發(fā)送端我想要的是從1001開始的數(shù)據(jù),即使中間發(fā)送了后面的數(shù)據(jù),接收端也不會進行確認,而是不斷的回復后沿數(shù)據(jù)的確認應答。而如果發(fā)送端連續(xù)三次收到了同一個確認應答,他就了解到了有數(shù)據(jù)的丟失,他此時就會對確認序號ack位置的數(shù)據(jù)進行重傳。
這樣的方法比之前的超時重傳要快,因為發(fā)送三次確認回復的時間比起等待超時要少了很多,所以這種機制也被稱為快速重傳機制。
為什么是三次?
三次提供了一個緩沖的時間,可以適當避免因為網(wǎng)絡(luò)延遲而導致的數(shù)據(jù)延遲到達。三次其實也是相當于一個確認,如果在第一次或者第二次后收到了該數(shù)據(jù),則就不會再發(fā)送后面幾條,發(fā)送端也不需要重傳。
延遲應答
接收方接收到數(shù)據(jù)后并不會馬上進行確認回復,因為一旦回復就會因為接收緩沖區(qū)的剩余空間變小,導致發(fā)送方的滑動窗口變小,使傳輸?shù)耐掏铝孔冃 ?br /> 所以引入延遲應答機制, 延遲一段時間,等待上層進行數(shù)據(jù)處理一段時間再進行答復,可能在應答的時候上層就已經(jīng)將數(shù)據(jù)取出了,這樣就保證了窗口的大小不會變小,吞吐量不會變慢,并且等待的時候上層也在處理,所以不會出現(xiàn)緩沖區(qū)不足的情況。
延遲應答保證網(wǎng)絡(luò)不擁塞的情況下盡量提高傳輸效率
捎帶應答
接收方接受到數(shù)據(jù)之后,需要進行確認回復。而確認回復其實就是在報頭中標記一個ACK確認序號,發(fā)送這樣的只有響應的空報文十分浪費,所以為了減少空報頭的響應占據(jù)帶寬,所以引入了捎帶應答機制,在即將要發(fā)送的數(shù)據(jù)頭部中加上上一條接收到的數(shù)據(jù)的確認回復。比如三次握手中第二次的ACK+SYN就是捎帶應答。
面向字節(jié)流
對于TCP來說,每當創(chuàng)建一個socket的時候,就會同時在內(nèi)核中創(chuàng)建一個接收緩沖區(qū)和發(fā)送緩沖區(qū)。
接收:對于接收到的數(shù)據(jù),并非像UDP一樣一條一條往上交付,而是先將接收到的數(shù)據(jù)放入緩沖區(qū),再根據(jù)上層所需要的長度,從接收緩沖區(qū)中取出相應的數(shù)據(jù)交付。
發(fā)送:對于發(fā)送的數(shù)據(jù)并不會直接發(fā)送,而是先存入發(fā)送緩沖區(qū)。如果數(shù)據(jù)過大,則會被拆分成多個TCP數(shù)據(jù)包發(fā)送。而如果數(shù)據(jù)過小,則會在發(fā)送緩沖區(qū)中等待,直到大小合適后再從發(fā)送緩沖區(qū)中取出數(shù)據(jù)發(fā)送(延遲發(fā)送可關(guān)閉)。
優(yōu)點:這種傳輸方式比較靈活,對于多個小數(shù)據(jù),會合并為一條大的數(shù)據(jù)一次性發(fā)送過去,這樣就大大的減少了IO的次數(shù)。接收方也更加靈活,他可以任意取出想要的數(shù)據(jù),不會像UDP一樣必須交付一條完整的報文。
缺點:因為數(shù)據(jù)會在緩沖區(qū)中進行合并或者拆分,這就導致了數(shù)據(jù)直接的邊界無法控制,所以TCP交付的這條數(shù)據(jù)可能并非一條完整的數(shù)據(jù),而是半條或者多條數(shù)據(jù),所以可能會導致上層會將多條數(shù)據(jù)按照一條來處理。這也就是TCP粘包問題。
TCP粘包問題:即TCP可能將多條數(shù)據(jù)按照一條處理(UDP不會有這種問題,UDP在首部中定義了數(shù)據(jù)報長度,確保每次只交付一條完整的數(shù)據(jù))
解決方案:需要我們自己進行邊界的管理。
1.每條數(shù)據(jù)之間以特殊字符進行間隔(如果數(shù)據(jù)中有該字符可能要轉(zhuǎn)義處理)
2.數(shù)據(jù)定長傳輸,不夠則補位(數(shù)據(jù)如果過短,則會傳遞大量無用的補位數(shù)據(jù))
3.應用層協(xié)議頭部定義數(shù)據(jù)長度(這里可以參考http協(xié)議和udp協(xié)議的做法)
http:頭部以\r\n\r\n表示結(jié)束,并且在頭部的Content-Length確定正文長度。
udp:傳輸層就解決了,在頭部中就已經(jīng)定義數(shù)據(jù)報長度。
基于TCP的應用層知名協(xié)議
- HTTP
- HTTPS
- SSH
- Telnet
- FTP
- SMTP
總結(jié)
以上是生活随笔為你收集整理的计算机网络 | 传输层 :UDP与TCP协议详解的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 计算机网络 | 应用层 :HTTP协议详
- 下一篇: 高级数据结构与算法 | AVL树 (高度