wordpress wordpress.orgseo推廣軟
文章目錄
- UDP協(xié)議
- UDP協(xié)議數(shù)據(jù)報(bào)
- 報(bào)頭
- TCP協(xié)議
- 確認(rèn)應(yīng)答
- 緩沖區(qū)
- 超時(shí)重傳
- 三次握手
- 其他問題
- 四次揮手
- 滑動(dòng)窗口
- 流量控制
- 擁塞控制
UDP協(xié)議
前面我們只是說了UDP協(xié)議的用法,但是并沒有涉及到UDP協(xié)議的原理
畢竟知道冰箱的用法和知道冰箱的原理是兩個(gè)層級(jí)的事情
我們首先知道計(jì)算機(jī)網(wǎng)絡(luò)世界是搭建在四層架構(gòu)上的
而HTTP協(xié)議是處于最頂層,是應(yīng)用層協(xié)議,應(yīng)用層協(xié)議的最大特點(diǎn)就是非常多,而且各異
這樣多的協(xié)議要在網(wǎng)絡(luò)中傳輸,必須得給他統(tǒng)一了,并且還能將底層收上來的數(shù)據(jù),正確的交付到各個(gè)端口中
做到這些的就是傳輸層協(xié)議,主要有兩個(gè),就是大名鼎鼎的UDP和TCP
UDP協(xié)議數(shù)據(jù)報(bào)
所有的協(xié)議都規(guī)定了兩部分,就是報(bào)頭和數(shù)據(jù)本身,在傳輸層我們一般習(xí)慣把這整體稱之為數(shù)據(jù)包
報(bào)頭
報(bào)頭是這樣的
相比于IP協(xié)議和TCP協(xié)議,UDP協(xié)議的報(bào)頭還是十分友好的
UDP的報(bào)頭大小是固定的,8字節(jié),因此當(dāng)我們獲取到一個(gè)UDP數(shù)據(jù)報(bào)之后,取前8個(gè)字節(jié),找到UDP數(shù)據(jù)報(bào)的總長度,就能完整的取到整個(gè)報(bào)文數(shù)據(jù)
需要注意的是,16位UDP長度指的是UDP數(shù)據(jù)報(bào)的總長度,包含報(bào)頭和數(shù)據(jù)部分,因此UDP的最大數(shù)據(jù)大小就是2^16-1,大小就是64KB
UDP的傳輸過程是不可靠的,無連接的,面向數(shù)據(jù)報(bào),在我們之前介紹的時(shí)候有說過,他的主要應(yīng)用場景其實(shí)就是直播了
TCP協(xié)議
TCP報(bào)頭就比UDP丑多了,而且他還是不定長的,其中有一個(gè)交4位首部長度,是代表了TCP報(bào)頭的大小,范圍是20到60字節(jié)
其他的部分都是用來確保TCP的可靠性和效率所用到的
TCP如此知名,就是因?yàn)樗目煽啃?那么他做了哪些事情保證他的可靠呢
確認(rèn)應(yīng)答
我們發(fā)出了一條信息,怎么確定對(duì)方是否看到了呢,在Line或者抖音中,會(huì)回顯對(duì)方是否已讀,這其實(shí)就是一個(gè)確認(rèn)應(yīng)答機(jī)制
為了保證可靠性,TCP協(xié)議規(guī)定了ACK機(jī)制,也就是確認(rèn)應(yīng)答機(jī)制
機(jī)智的朋友肯定發(fā)現(xiàn)上面的標(biāo)志位中有一個(gè)ACK,就是用于這個(gè)事情的
但是如果服務(wù)器和客戶機(jī)一人一條發(fā)送,服務(wù)器每發(fā)送一個(gè)數(shù)據(jù),都要等客戶端回答收到之后再發(fā)送,這樣固然是可靠了,但是效率卻也大大降低了
于是就有了下面的想法,一次發(fā)送10條數(shù)據(jù),分別標(biāo)記上1到10
客戶端收到1回復(fù)2,表明自己的1收到了,下一個(gè)想要2,因此客戶端在一次收到1到10之后會(huì)分別回復(fù)2到11
但是計(jì)算機(jī)網(wǎng)絡(luò)紛繁復(fù)雜,數(shù)據(jù)報(bào)可不一定是按順序到達(dá)的,這就麻煩了,我怎么知道我缺哪個(gè)呢,而且每一個(gè)都進(jìn)行回復(fù)也太二了
然后我們?cè)傧?一次發(fā)送了1到10,但是接收到了,1到5,8到10,6和7都丟了
那我們只回復(fù)5,標(biāo)識(shí)5以前的都正確收到了,接下來想要6
這樣就好很多了
緩沖區(qū)
除此之外,TCP的協(xié)議是全雙工的,用一個(gè)端口就可以執(zhí)行發(fā)送和接收兩個(gè)操作,而且系統(tǒng)調(diào)用recv和read也不是從網(wǎng)卡中讀取數(shù)據(jù)到內(nèi)存,而是從緩沖區(qū)里拿上來的,send和write其實(shí)也算寫入到緩沖區(qū)的,不是直接寫到網(wǎng)卡里
那這個(gè)緩沖區(qū)寫滿了怎么辦,怎么知道,發(fā)送緩沖區(qū)沒數(shù)據(jù)了怎么辦
這其實(shí)就是那16位的窗口做的事情,他分別對(duì)應(yīng)了緩沖區(qū)的大小,每一次收發(fā)其實(shí)都會(huì)把緩沖區(qū)的狀態(tài)寫在里面,當(dāng)緩沖區(qū)都快滿了,寫方就知道不要再往里面?zhèn)髁?/p>
超時(shí)重傳
當(dāng)數(shù)據(jù)在傳輸過程中丟了怎么辦,遲遲沒有收到ACK就說明發(fā)送失敗了
當(dāng)服務(wù)器等了一段時(shí)間也沒有收到客戶機(jī)發(fā)來的ACK,就說明數(shù)據(jù)可能是丟了,無論是數(shù)據(jù)丟了,還是ACK丟了,都會(huì)觸發(fā)超時(shí)重傳
這時(shí)候TCP協(xié)議就會(huì)要求服務(wù)器重新傳一次數(shù)據(jù)
一般來說這個(gè)一段時(shí)間其實(shí)是動(dòng)態(tài)的,各家操作系統(tǒng)都是這樣
邏輯是這樣的500ms是一個(gè)單位,每次乘2,當(dāng)次數(shù)有幾次之后,就說明對(duì)方主機(jī)可能出毛病了,有可能是被拔網(wǎng)線了,這時(shí)候就不會(huì)重傳了
其實(shí)TCP協(xié)議他可靠嗎,確實(shí),在他能做到的范圍內(nèi)確實(shí)可靠,但是如果被拔網(wǎng)線就沒辦法了(不可抗力)
三次握手
我們說TCP協(xié)議是面向連接的,這個(gè)連接是怎么建立的呢
就是通過三次握手,在TCP報(bào)頭中的SYN標(biāo)記就是標(biāo)識(shí)我要跟你交朋友
過程是這樣的
客戶端發(fā)起請(qǐng)求,說,我要跟你做朋友(發(fā)送一個(gè)包含SYN標(biāo)記的報(bào)文)
服務(wù)端收到之后,說,我收到了你的消息,我也要跟你做朋友(發(fā)送了一個(gè)ACK和SYN標(biāo)記都有的報(bào)文)
客戶端收到之后,說,好!(發(fā)送一個(gè)ACK標(biāo)記的報(bào)文)
這三次數(shù)據(jù)傳遞其實(shí)就建立了一個(gè)TCP連接,但是建立連接的時(shí)候,是在哪一個(gè)動(dòng)作呢
其實(shí)是在客戶端最后一次發(fā)送之后,客戶端就認(rèn)為連接建立好了,而服務(wù)器接收到了之后,服務(wù)器就認(rèn)為連接建立好了
接下來客戶端就可以發(fā)送請(qǐng)求了,瘋狂星期四,V我50
需要注意的是,服務(wù)器可不是一次只跟一個(gè)客戶機(jī)聊天,說不定有成千上萬的客戶端來請(qǐng)求,而操作系統(tǒng)的管理策略其實(shí)就是先描述再組織,將這些連接管理起來
其他問題
有一個(gè)經(jīng)典的面試問題為什么是三次握手,其他次數(shù)行不行
- 偶數(shù)次
這里需要知道一點(diǎn),當(dāng)我發(fā)出一條消息的時(shí)候,我是不知道這條消息能不能傳達(dá)到的,但是可以確定的是,我之前的消息一定傳到了,并且我也可以收到對(duì)方的消息
而在這個(gè)過程中,永遠(yuǎn)是客戶機(jī)給服務(wù)器發(fā)送請(qǐng)求,如果是奇數(shù)次,說明最后一個(gè)確認(rèn)是服務(wù)器發(fā)給客戶端的,說明之前的信息都沒問題了,為什么還要繼續(xù)確認(rèn)呢?我直接發(fā)我的請(qǐng)求不好嗎
而且如果使用偶數(shù)次握手,是服務(wù)器先確認(rèn)建立的連接,客戶端就可以一直發(fā)送SYN報(bào)文,一直不建立連接,服務(wù)器需要面對(duì)的可就多了,維護(hù)連接過多可是會(huì)掛掉的
- 其他奇數(shù)次呢
1次就不說了太蠢了,5次以上那不就是浪費(fèi)資源了
3次就能干好的事情為什么要5次7次,那不是脫褲子放屁嗎
四次揮手
有資源的申請(qǐng)就要有資源的釋放,有鏈接的申請(qǐng)就要有鏈接的釋放
在TCP報(bào)頭中有一個(gè)叫做FIN,其實(shí)就是final,標(biāo)志著我要離開我的朋友了
鏈接的釋放可以說客戶端也可以是服務(wù)器,這里我為了方便表示說是客戶端,表示我要的資源已經(jīng)拿到了,要拜拜了
客戶端發(fā)出請(qǐng)求,要拜拜了(發(fā)送一個(gè)帶有FIN的報(bào)文)
服務(wù)器收到了,我知道了(原地等待一會(huì)兒)(返回一個(gè)ACK,表示我知道了,然后等待一個(gè)CLOSE_WAIT的時(shí)間,給客戶機(jī)反悔的機(jī)會(huì),看客戶機(jī)還有沒有別的話說)
這段時(shí)間服務(wù)器什么也沒有等到,服務(wù)器說,這是我跟你說的最后一句話,以后再也沒有了(假),拜拜(發(fā)送了一個(gè)LAST_ACK,表示最后一個(gè)ACK報(bào)文,并且附帶了FIN標(biāo)志,表示結(jié)束)
當(dāng)客戶端收到之后,其實(shí)連接就已經(jīng)斷開了,并且會(huì)維持一段時(shí)間TIME_WAIT,不讓客戶端對(duì)同一個(gè)端口發(fā)送請(qǐng)求,咱不能抓著一只羊薅羊毛吧
滑動(dòng)窗口
如果服務(wù)器發(fā)送了1到20號(hào)數(shù)據(jù),但是客戶端收到的是1和3到20,只發(fā)了一個(gè)2的請(qǐng)求,服務(wù)器看到之后覺得他只收到了1,于是把2到20又發(fā)了一遍,這樣的效率又變得不行了
于是就有了滑動(dòng)窗口,我們把發(fā)送緩沖區(qū)和接收緩沖區(qū)想象成數(shù)組,兒窗口限制的其實(shí)是左右的下標(biāo),我們每次只確認(rèn)窗口中的數(shù)據(jù)即可
需要注意的是,在滑動(dòng)窗口中的每一個(gè)部分其實(shí)都是需要確認(rèn)ACK的,這是和之前不一樣的
流量控制
流量控制其實(shí)用到的原理就是上面的滑動(dòng)窗口,我們需要控制發(fā)送數(shù)據(jù)的速度,不能讓接收端的緩沖區(qū)過滿,不然就是無用功了
這時(shí)候TCP報(bào)頭中的顯示緩沖區(qū)情況就起到作用了
擁塞控制
擁塞控制與流量控制不同,他是為了防止網(wǎng)絡(luò)狀況不好產(chǎn)生的原因,比如說路由器出問題,網(wǎng)絡(luò)擁堵送不出去
TCP的解決方案是慢啟動(dòng),他指的是一開始的發(fā)送的數(shù)據(jù)很少,但是是指數(shù)級(jí)別的增長
當(dāng)這個(gè)增長達(dá)到一定閾值之后,就是用線性增長了,如果遇到了重傳,就會(huì)減半