目錄
一.UDP協議
1.1UDP協議的特性
1.2UDP協議段格式
1.3UDP緩沖區
1.4UDP常見的應用場景
二.TCP協議
2.1TCP的特性
2.2面向連接
2.2.1針對三次握手的面向連接
a.雙方發送資料包名稱
b.雙方連接狀態
2.2.2針對四次揮手的面向連接
a.雙方發送資料包名稱
b.雙方連接狀態
c.2MSL
d.埠重用
e.CLOSE_WAIT狀態
2.2.3面向連接之包序管理
a.網路抓包
b.三次握手當中三次的包序號
2.3TCP協議的協議欄位
2.4可靠傳輸
2.4.1保證可靠
a.確認應答機制
b.超時重傳機制
2.4.2保證傳輸效率
a.提高發送方發送的效率&接收方接受的能力
b.網路的轉發能力
2.5面向位元組流
一.UDP協議
1.1UDP協議的特性
特性:無連接,不可靠,面向資料報
- 無連接:UDP客戶端給服務端發送訊息的時候,不需要和服務端先建立連接,直接發送(客戶端也是不清楚服務端是否正在在線)
- 不可靠:UDP并不會保證資料是可靠有序到達對端
- 面向資料報:UDP資料不管是和應用層還是網路層傳遞,都是整條資料交付的
1.2UDP協議段格式
如下圖所示,這里的資料又叫做有效載荷(應用層的資料)

- 16位源埠:當前的UDP資料從那一個行程產生
- 16位目的埠:當前的UDP資料想要去往哪一個行程
- 16位UDP長度:UDP資料的最大傳輸資料大小,它由兩部分組成:UDP協議報頭+UDP負載資料(這里指應用層遞交給UDP資料);它的最大資料長度是2^16,UDP最大的傳輸大小是65536位元組,
- 16位UDP校驗和:校驗資料在傳輸的程序是否失真,如果失真了,UDP協議就會將該UDP資料報丟棄;如果沒有失真,則當應用層呼叫recvfrom函式的時候,就會將UDP資料報給到應用層,
常見的面試題:
- UDP傳輸的資料最大的大小是多少?答:65536位元組
- 如果想要傳輸要比2^16更大的資料應該這樣做呢?答:在應用層針對資料進行分片,將超過65536位元組的資料包進行拆分,將拆分后不超過65536位元組的資料遞交給傳輸層的UDP協議打上UDP包頭,此時在傳輸層存在多個獨立的UDP資料包,因此在應用層需要描述分包出來的UDP片段,所以我們在應用層不僅要對資料進行分片還有對其進行描述,在其前面打上應用層包頭,是我們自己定義的里面有標識,標志位和片偏移,

1.3UDP緩沖區
- 發送緩沖區:沒有真正意義上的發送緩沖區,呼叫sendto會直接交給內核,內核將該資料傳給網路協議進行后續的傳輸動作,也就是將應用層提交給傳輸層的應用層資料打上報頭之后就提交給網路層繼續傳輸
- 接受緩沖區:去掉UDP報頭之后,將資料遞交給應用層,它具有接識訓沖區,但不保證資料的可靠,以及有序,
- UDP的socket既能讀又能寫,這個概念叫做全雙工,
1.4UDP常見的應用場景
基于UDP的應用層協議:
- DNS:域名決議
- DHCP:動態主機分配協議,誰上網給誰分配IP,同一個局域網內部可能使用UDP,因為網路穩定
- NFS:網路檔案系統
二.TCP協議
2.1TCP的特性
特性:面向連接,可靠傳輸,面向位元組流
- 面向連接:雙方在發送網路資料之前必須先建立連接,再進行發送
- 可靠傳輸:保證資料是可靠并且有序到達對端(有序是針對應用層而言的,TCP能夠確保的是該條資料到達對端的應用層時,一定是有序到達的,到達傳輸層的時候有可能不是)
- 面向位元組流:多次發送資料在網路傳輸當中沒有明顯的資料邊界(對于沒有明顯間隔的資料橙稱之為TCP粘包問題)
2.2面向連接
2.2.1針對三次握手的面向連接
a.雙方發送資料包名稱
三次握手時雙方發送資料包的名稱如下圖:

客戶端呼叫connect介面發起三次握手,他會給服務端發送SYN資料包(連接資料包),服務端接收到SYN資料包后,通常會回復一個ACK+SYN資料包(ACK在這里的作用是服務端用來確認客戶端發送給服務端的SYN資料包服務端接收到了,SYN在這里反映了服務端也想要和客戶端進行連接),此時客戶端給服務端發送ACK資料包,用來確認服務端發送個客戶端的SYN資料包客戶端收到了,
b.雙方連接狀態
如下圖所示:

當客戶端發出去SYN資料包時,此客戶端處于SYN_SENT狀態,這是TCP中的一個狀態,說明將SYN發送出去了,當服務端接收到SYN資料包時,服務端狀態變成SYN_RCVD,當服務端給客戶端發送了一個ACK+SYN資料包時,并且客戶端收到了這個資料包,此時客戶端的狀態變成了ESTEBALISHED表示連接已經建立,此時客戶端認為連接已經建立,但是此時服務端并不認為連接是已經建立的,換一句話說當前的連接還在內核的未完成連接佇列當中,即使此時服務端去呼叫accept(),也不會將連接從內核中拿出來,除非當客戶端給服務端發送ACK資料包時,服務端的狀態變成ESTEBALISHED狀態,這時當前連接才會從內核的未完成連接佇列中放到已完成連接佇列中去,此時在呼叫accept()時才會獲取到連接,
根據上面分析,TCP必須握手三次才能建立連接的原因:
- 從雙方連接狀態的角度,當兩次握手時雖然客戶端認為連接已經建立,但是服務端此時狀態表示連接并未建立,并且該連接此時還在內核當中的未完成連接佇列當中,即使呼叫accept函式頁不會獲取到連接;
- 從確認客戶端接受能力的角度,當客戶端此時發送SYN資料包給服務端,此時服務端收到了,說明他的接受能力是沒有問題的;服務端發送ACK_SYN資料包給客戶端,表示他的發送能力是沒有問題的;而此時客戶端收到了這個資料包表示了此時客戶端的發送與接收能力是沒有問題的,但是如果此時沒有客戶端發送給服務端ACK資料包,那么服務端并不能確定客戶端是否收到了ACK_SYN資料包,它是沒有辦法檢測客戶端的接受能力的,那么就服務端就不會認為已經建立連接,
2.2.2針對四次揮手的面向連接
四次揮手并不限定于兩者誰先斷開連接,雙方都有可能先斷開連接,在這里我們設定雙方為注定斷開連接方與被動斷開連接方,我們在這里簡稱a方與b方,
a.雙方發送資料包名稱

a方在這里會主動發起一個FIN報文,b方在收到FIN報文后會回復一個ACK(表示發送的FIN報文b方收到了),緊接著b方再發送一個FIN報文(回應斷開連接),然后a方收到后,在對b方發送一個ACK表示確認,此時四次揮手結束,
b.雙方連接狀態

當a方發送FIN報文給b方時,此時a方會從ESTEBALISHED狀態變成FIN_WAIT_1狀態;當b方收到FIN報文后會變成CLOSE_WAIT狀態,與此同時會給我們a方回復一個ACK,當a方接收到后會從FIN_WAIT_1變成FIN_WAIT_2狀態,
b方會在主動給a方發送FIN報文,此時b放的狀態會從CLOSE_WAIT狀態變成LAST_ACK狀態;當a方收到FIN報文后,此a方時狀態變成了TIME_WAIT狀態,并且給b方回復了一個ACK,然后b方的狀態會變成CLOSED狀態,而a方會等一段時間(這段時間我們稱之為2MSL)變成CLOSED狀態,
c.2MSL
在進行理解2MSL之前,我們必須知道,只有主動斷開連接方才會有TIME_WAIT狀態,MSL指的是報文最大生存時間,即時自發送方發送出去之后,發送方認為該報文的最大生存時間是MSL,我們還需理解當發送方發送一個資料,需要接收方進行確認的機制叫做確認應答機制,但是為什么要等待2MSL呢?如下圖所示:

在b方位LAST_ACK狀態下給a方發送了FIN報文,此時a方會再給b方回復發送ACK,假設此時ACK并未傳輸到b方,而是在程序中丟失了,那么b方就不清楚FIN報文是否到達a方,如果此時b方等待很久沒有等到回復的ACK,那么它就會再向a方發送FIN報文,那么a方就會重置它的狀態,會再進行等待一個2MSL,我們將這種機制稱之為超時重傳機制,
2MSL由兩部分組成一部分是ack資料的MSL+被動斷開連接方重傳的FIN報文(兩種情形,FIN還未到達主動斷開連接方就丟失;主動斷開連接放回復的ACK丟失了);如果說等待了2MSL的時間,也沒有等到重傳的FIN報文,則說明ACK資料一定到達了被動斷開連接方,那么主動斷開連接方狀態變成CLOSED,
d.埠重用
處于TIME_WAIT狀態的程式,還需要將埠占用著,等待2MSL之后,在釋放呼叫埠,占用埠的原因是防止被動斷開連接方重傳FIN報文,但是在這里如果當服務端作為主斷開連接方,并且服務端行程還退出了想要快速啟動服務端程式就會出現如下問題,
- 服務端程式當中埠是寫死的27878
- 服務端有可能就陷入到TIME_WAIT狀態,等待2MSL才能將埠釋放(行程退出了,但是當前的埠還在被網路協議堆疊占著)
由于上面的這兩點,如果想要快速啟動服務端程式時就會報錯bind:Address areadly in use.因此我們引入埠重用,直接呼叫下面埠,
int opt = 1;
setsockopt(listenfd, SOL_SOCKER, SO+REUSEADDR, &opt, sizeof(opt));
- listenfd:套接字描述符
- SOL_SOCKER:套接字選項
- SO+REUSEADDR:重用埠
- opt: opt=1
- sizeof(opt):長度
e.CLOSE_WAIT狀態
只有被動斷開連接方才會存在的狀態,處于CLOSE_WAIT一方需要呼叫close函式關閉新連接的套接字,如果被動斷開連接方存在大量的CLOSE_WAIT狀態,那么需要check代碼當中是否有阻塞,回圈導致被動斷開連接無法呼叫到close,在CLOSE_WAIT狀態到LAST_ACK狀態中,需要被動斷開連接方呼叫close函式,且被動斷開連接方還可以給主動斷開連接放發送一些資料,
2.2.3面向連接之包序管理
a.網路抓包
- 在win作業系統下:wireshack,針對網卡進行抓包
- 在linux作業系統下:可以抓任意協議下的資料包,并不只能抓TCP下的資料包,命令范式:tcpdump -i any port [抓取資料的埠] -s 0 -w [將抓取的埠寫到的檔案]
上面的命令如果去掉port [抓取資料的埠],則沒有使用埠進行過濾,那么抓出來的資料包比較大,一般將抓出來的檔案通過wireshark進行分析,
在這里注意:想要看到三次握手后的程序,需要先開啟抓包,再啟動程式,
b.三次握手當中三次的包序號
在三次握手發送資料包的程序當中,在TCP中分別維護了兩套序號,一套是客戶端在維護,一套是服務端在維護,我們現在來分析一下三次握手當中三次的包序號,如下圖所示:

客戶端個服務端發送SYN資料包,資料包中攜帶的序號Seq=0;服務端收到后給客戶端回復一個ACK+SYN資料包,包中攜帶的序號ACK=1+seq=0,此時ACK=1服務端就告訴客戶端期望下次發送資料是從1號序號開始的,seq=0服務端之后給客戶端發送資料的起始序號是從0開始的,緊接著客戶端給服務端發送一ACK,攜帶的序號為seq=1,ack=1,此時的ack=1是用來確認服務端個客戶端發送的seq=0,在這里客戶端確認了收到了0號資料包且期望下次資料是從1號序號開始的,
緊接著上面的圖,我們再對下圖進行分析:

在紅色標記部分我們發現客戶端給服端發送了兩次資料,但是他們的seq都是為1,原因時純的ACK資料包時不消耗序號的,不消耗序號即意味著不需要對方進行確認,也就是說,在三次握手的時候,最后客戶端給服務端發送的Seq=1的序號并沒有真正被消耗掉,而是在建立連接之后客戶端給服務端發送Seq=1的時候,1號序號才被消耗掉,此時需要服務端確認是否收到該識別符號,
我們再分析下圖:

結論:在這里我們也要注意TCP在發送資料的時候,資料的每一個位元組都會進行標識,
總結:
- TCP連接當中維護了兩套序號,客戶端維護了一套,服務端維護了一套
- 雙方再給對方發送資料的時候,是消耗自己維護的序號
- 接收方再確認發送的資料的時候,是以期望下一個序號的方式進行確認
- 雙方在三次握手當中協商各自序號的起始位置,需要注意的是,雙方的起始位置不一定從0開始,可以從任意位置開始,只需要后續遵守起始位置進行發送即可
- 服務端發送個客戶端的資料是由客戶端進行確認,客戶端發送給服務端的資料是由服務端進行確認
在這里存在的問題:
三次握手建立之后可以雙發可以正常發送資料嗎?答:不會,因為在三次握手之后在沒有呼叫accpet函式的時候連接還是處在內核當中的已完成練級佇列當中,并沒有被呼叫回來,
2.3TCP協議的協議欄位

- 16位源埠,16位目的埠
- 32位序號:用來表示TCP資料的起始序號
- 32位確認序號:ack告知對端,自己期望對端下一次發送資料的時候從哪一個序號開始
- 4位首部長度(1111=>15),他計算出來的是一個數值而并非是位元組,首部長度占用位元組數量=4位首部長度計算出來的數值*4(1111=>15*4=60位元組),因此TCP頭部最大為60位位元組最小為20位位元組,
- 標志位:URG:緊急標志位(MSG_OOB緊急資料,帶外資料);ACK:確認標志位;PSH:發送資料標志位;RST:重置連接標志位;SYN:發起連接標志位;FIN:斷開連接標志位
- 16位視窗大小:牽扯到滑動視窗機制
- 16位緊急指標:配和URG標志位一起來使用,傳輸緊急資料
- 選項:MSS:最大報文段長度,他是TCP雙方在三次握手程序中協商最大報文長度的大小,客戶端會告訴服務端有MSS_cli,服務端會告訴客戶端MSS_svr,雙方在三次握手的程序中都會發送他們最大報文的長度,而雙方采用以最小的MSS作為后續傳輸資料的時候的最大報文長度,min(MSS_cli,MSS_svr),它的作用是TCP在傳輸資料的時候,嚴格按照MSS進行傳輸,MSS的大小與本地的網卡息息相關,即MSS+ipheader+tcpheader<=MTU;MTU是最大傳輸單元(資料鏈路層對網路資料的限制),每一個網卡都有最大的傳輸單元他是資料鏈路層對網路資料的限制他是依照傳輸電器的特性決定的,因此MSS一定小于MTU,TCP在每次發送資料的時候,資料的大小都不會超過MSS,只用TCP有MSS的限制,UDP是沒有的(uint_16),
2.4可靠傳輸
2.4.1保證可靠
a.確認應答機制
回復確認資料包的作業,在網路協議堆疊的TCP協議自己就完成了,不需要程式員的介入,而程式員只需要關心的是recv函式從接識訓沖區拿資料,
b.超時重傳機制
當發送方發送了一個資料之后,就會開啟一個重傳計時器,當重傳計數器記錄的時間超過重傳時間,則會重傳該報文,
假設發送方給接收方發送了一個訊息,在發送的同時會開啟一個重傳計時器,重傳計時器超時的兩種可能,一種是發送方發送訊息時訊息丟失;另一種是接收方在確認資料報在網路中丟失了,不管是那種情況,對于發送方而言,都不能確定有沒有到達接收方,超時時間之后則會重傳訊息,
那么超時重傳的時間是固定的嗎?并不是,因為網路的轉發能力不是一成不變的,
RTO:超時重傳時間 RTT:報文往返時間 RTO:2*RTT
RTT(預測本次資料包的報文往返時間) = RTT(prev前一段時間)*0.9 + RTT(pprev前前一段時間)*0.1
2.4.2保證傳輸效率
a.提高發送方發送的效率&接收方接受的能力
滑動視窗機制
- 前提:TCP在確認應答機制和超時重傳機制下,已經可以保證資料時可靠有序到達對端,但是如果單單只有該兩個機制,就會導致TCP的發送發在發送下一個資料之前,會等待上一個資料的確認應答,這樣的整體發送效率會比較低,
- 機制:滑動視窗機制允許一次性發送多個分組(每個分組的大小不會超過MSS)到網路當中進行傳輸,當發送方接收到最早分組的確認應答之后,視窗可以向后滑動,包括下一個可以發送的分組,
- 實作效果:滑動視窗機制提高發送方和接收方的吞吐能力,提高了雙方傳輸的效率,
問題:TCP在雙方發送資料的時候,TCP發送維護的視窗大小時一成不變的嗎?
首先我們理解滑動視窗是指允許一次性丟到網路當中分組的集合,而分組的個數就是視窗的大小,發送方視窗是動態變化的,取決于接收方通告的視窗大小,
- 前提:TCP協議欄位當中"16位視窗大小";訊息發送方告知訊息發送方,訊息接收方的接受能力的欄位,

- 當TCP的接收方接收到資料之后,會將給資料先快取在TCP的接識訓沖區當中,TCP的接識訓沖區的大小并不是無限制的,一旦應用層不呼叫recv從接識訓沖區當中獲取資料時,就會導致TCP接受緩沖區隨著一直接收發送方發送的資料而接受緩沖區的大小逐漸變小,
結論1:接收方通過視窗大小,告知發送方位元組的接受能力;接收方在發送資料的時候,會按照接收方通告的接受能力動態的調整自己的發送資料量(視窗大小),這就是在滑動視窗地下的流量控制,TCP流量控制(TCP的流控制),就是TCP通過當前協議欄位當中的"視窗大小"欄位來控制雙方發送資料的資料量,
結論2:如果雙方的發送資料的兩不加以控制,則可能會導致接收方由于接收能力不足,而將發送方發送的資料丟棄掉,觸發超時重傳機制,如此往復,網路中就會充斥大量的重傳資料包,占用寬帶資源,導致整個網路的轉發能力變差,
0號視窗

如上圖所示, 當發送方接收到"0號視窗"之后,就會將滑動視窗當中的視窗大小調整為0,暫時不發送資料到對端,在這里有兩種恢復發送方給接收方發送資料,
- 發送方主動給接收方發送視窗探測包,詢問接收方的接受能力,注意,視窗探測包的資料的大小位固定的1位元組,
- 接收方主動給發送方發送視窗更新通知,
滑動視窗丟包
(1)丟失某個分組的ACK

當主機A分了六組發送資料,但是此時主機B給出的確認應答卻在傳輸中丟失了,如上圖在確認序號一個是1001號時的確認應答丟失了,但是下一個確認應答達到對端了,那么2001之前的所有序號資料主機B都受到了,就不需要主機A進 行重傳了,當視窗當中某個分組的ACK丟失后,可以通過收到的高確認序列號來確認丟失ACK的分組資料是否到達對端,
(2)丟失某個分組資料

結論:如果資料丟失則一定要重傳, 如圖所示,接收方的接識訓沖區有一個功能,它會將缺失的資料之后的所有資料快取到接識訓沖區當中,雖然接收方的接識訓沖區已經拿到這些資料,但在recv()進行呼叫時不能被拿走,不被拿走是因為當前前面缺失了資料,如果他拿走了這些資料,那么TCP就沒有保證資料的有序,那么在這里遞交給應用測的資料不是有序的,但是TCP是面向位元組流的,就會導致應用層不會知道資料的順序是什么,那么處理的資料就不是唯一的,
擁塞控制機制:慢啟動,擁塞避免,快重傳,快恢復
擁塞控制+流量控制:作用TCP的雙方對發送資料的速率,提高了TCP的發送速率,
問題:一開始就要按斬訓動視窗的大小發送資料嗎?
否,沒有考慮到網路的轉發能力是否能夠滿足一次性傳輸(轉發)視窗的大小,
- 網路傳輸的時候,資料實在共享網路當中進行傳輸的,換句話數,網路被多個網路收發雙方所使用,同時在轉發多個人資料,
- 網路鏈路當中的路由器/交換機,轉發能力是有上限的,
- 網路鏈路當中的傳輸介質(光纖/雙絞線)是有傳輸上線的,
結論:TCP雙方在發送資料的時候,為了不是因為網路原因,頻繁的重傳,則TCP雙方在發送資料的時候,也考量網路轉發能力,
擁塞控制機制
他本質也是在控制發送方發送資料的量,因此最終發送的資料量=min(發送方的滑動視窗大小(取決于接收方的接受能力),擁塞控制機制當中的擁塞視窗大小(取決于網路擁塞程度)),
- 慢啟動:TCP通信雙方在建立連接之后,先發送少量的資料(擁塞視窗資料),探測網路的轉發能力(根據TCP資料包的往返時間),根據網路轉發能力,主動調節擁塞視窗大小,(擁塞視窗的大小位1個分組(1個MSS)),擁塞視窗的大小隨著傳輸輪次的增加呈指數增長,慢開始門限時在擁塞視窗大小小于慢開始門限的時候,是呈指數增長,當擁塞視窗大小超過慢開始門限,則切換為擁塞避免演算法,擁塞視窗大小從指數增長到線性增長的原因,往網路中丟入的資料是依次加大的,但是網路的轉發能力是有限的,就會導致TCP資料丟包(一旦發現有網路資料丟包了,發送方就會認為網路擁塞了,立即下調擁塞視窗大小),
- 擁塞避免:隨著輪次的增加,擁塞視窗大小呈線性增長(一次交1個分組)
- 快重傳:當發送方發送的網路資料包丟失后,發送方還沒有觸發超時重傳機制的時候,由接收方快速的確認丟失報文的起始序號,告知發送方該報文丟失,則發送方不需要等到超時之后再重傳,它不會阻塞發送方的發送視窗的向后滑動的程序,也就是不會阻塞發送方發送的速率,
- 快恢復:早期TCP發現網路擁塞之后,是將擁塞視窗調整為1(即一個分組),從慢開始重新增長擁塞視窗的大小,重新調節面開始門限(新的慢開始門限 = 擁塞視窗發生時,擁塞視窗的一半);現在的做法是快恢復,一旦發現網路擁塞,則計算機的慢開始門限從新的慢開始門限執行擁塞避免演算法,
b.網路的轉發能力
- 延時發送機制:NAGLE演算法:如果當前發送方存在少量資料需要發送,則稍微等一下,等待資料量變大,在統一進行發送,但是工業場景中都是禁止使用演示發送的,比如說機械制造業,醫療領域,金融領域,
- 捎帶應答機制:運用于雙方都想給對方發送資料的場景,快速的進行互動,就將ACK放到PSH資料包當中攜帶給對方
- 延時應答機制:接收方收到了資料,為了給訊息發送通告更大的視窗大小,等待一段時間,如果在這段時間內,應用層將資料從(recv函式)接識訓沖區當中接收走后,接收方在恢復確認的時候,就可以給發送方通告更大的視窗大小了,
- 心跳機制(TCP保活機制):判斷空閑連接的雙方是否是正常狀態,如下圖,在連接空閑的時候,就會啟動一個保活計時器,記錄連接空閑的時間,一旦當連接的空閑時間超過2小時,則則主機BDE TCP協議會主動給主機A發送保活探測包(心跳包),如果主機B一直沒有收到探測包的應答,則會每75s發送一次,總共發送10次,如果10次探測包都沒有應答,則認為對端已經處于不正常狀態,則主動斷開連接,如果有應答,則認為連接正常,重新啟動保活計時器進行計時,

2.5面向位元組流
- 從發送資料的角度理解:應用層的應用程式在發送資料的時候,時呼叫send函式將應用層資料遞交給傳輸層的TCP協議,掉交給TCP協議之后,資料是暫時保存在發送緩沖區當中,但是一定不要認為TCP在發送資料的時候,是按照應用程式呼叫send函式的規律來進行發送的,TCP發送的資料一定是小于MSS,有自己發送資料的規律、
- 從接收的角度理解:但資料到達接收方的接識訓沖區之后,接收方的應用程式呼叫recv函式可以接收任意位元組,
面向位元組流服務會導致資料之間沒有邊界,產生TCP粘包問題,這就引出一個問題,如何解決TCP粘包問題,在應用程自定制協議-->應用層頭部+應用層數+間隔符,(完整講解)
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/298635.html
標籤:其他
下一篇:HCIA 第二天 基礎概念
