制詳解)
上篇文章我為大家介紹和演示了關(guān)于 UDP 和 TCP 兩個(gè)協(xié)議的網(wǎng)絡(luò)編程兩個(gè)協(xié)議的網(wǎng)絡(luò)編程還是有一定的區(qū)別我個(gè)人感覺(jué) TCP 的網(wǎng)絡(luò)編程會(huì)比 UDP 的復(fù)雜不少也更需要我們?nèi)ダ斫獠⑶沂炀毜卣莆?。這篇文章我將為大家介紹關(guān)于 TCP 協(xié)議中的十大核心機(jī)制。TCP 的特點(diǎn)有連接可靠傳輸面向字節(jié)流全雙工1. TCP 報(bào)文段首部格式解析2. 十大核心機(jī)制1.確認(rèn)應(yīng)答2.超時(shí)重傳3.連接管理4.滑動(dòng)窗口5.流量控制6.擁塞控制7.延時(shí)應(yīng)答8.捎帶應(yīng)答9.面向字節(jié)流10.異常情況TCP 報(bào)文段首部格式解析在講解十個(gè)核心機(jī)制之前我們先對(duì)這張表進(jìn)行一個(gè)大概的了解16位源端口號(hào)發(fā)送方應(yīng)用程序的端口號(hào)告訴接收方我是誰(shuí)16位目的端口號(hào)接收方應(yīng)用程序的端口號(hào)告訴網(wǎng)絡(luò)要把數(shù)據(jù)傳輸給誰(shuí)32位序列號(hào)數(shù)據(jù)包的編號(hào)TCP將一個(gè)大的數(shù)據(jù)拆分成很多個(gè)小塊進(jìn)行發(fā)送這個(gè)序列號(hào)給數(shù)據(jù)塊排隊(duì)使用接收方收到亂序的包后可以根據(jù)這個(gè)序號(hào)把它們重新拼成正確的順序。32位確認(rèn)序列號(hào)期望下一個(gè)收到字節(jié)的序列號(hào)這是接收方給發(fā)送方的反饋意思是“在這個(gè)序號(hào)之前的數(shù)據(jù)我都收到了請(qǐng)發(fā)下一個(gè)”。它是TCP可靠傳輸?shù)暮诵摹?位首部長(zhǎng)度表示TCP頭部有多長(zhǎng)告訴接收方數(shù)據(jù)從哪里開(kāi)始讀取。圖中右側(cè)標(biāo)注的“20 字節(jié)”指的是標(biāo)準(zhǔn)頭部的最小長(zhǎng)度。保留6位暫時(shí)不需要設(shè)置設(shè)置為0。這個(gè)是吸取了UDP的教訓(xùn)URG (Urgent):緊急指針有效表示包里有緊急數(shù)據(jù)需要優(yōu)先處理。ACK (Acknowledgment):確認(rèn)序號(hào)有效。連接建立后所有傳送的報(bào)文段都必須把ACK置為1。PSH (Push):提示接收方盡快把數(shù)據(jù)交給應(yīng)用程序不要在緩存里賴著。RST (Reset):連接出錯(cuò)要求復(fù)位重置連接。SYN (Synchronize):非常重要。用于發(fā)起一個(gè)新連接。我們?cè)凇叭挝帐帧苯⑦B接時(shí)主要看這個(gè)標(biāo)志。FIN (Finish):結(jié)束連接。表示“我說(shuō)完了我要掛電話了”。16位窗口大小接收方告訴發(fā)送方我現(xiàn)在還可以接收多少數(shù)據(jù)流量控制。如果接收方處理不過(guò)來(lái)窗口大小變小發(fā)送方就會(huì)減慢發(fā)送速度防止把接收方“撐死”。16位校驗(yàn)和用于校驗(yàn)數(shù)據(jù)在傳輸?shù)倪^(guò)程中是否損壞接收方收到數(shù)據(jù)后會(huì)算一遍如果算出來(lái)的結(jié)果和這個(gè)值不一樣說(shuō)明數(shù)據(jù)出錯(cuò)了比如路上被干擾了這個(gè)包就會(huì)被丟棄。16位緊急指針只有當(dāng) URG 標(biāo)志為 1 時(shí)才有效。它告訴系統(tǒng)緊急數(shù)據(jù)在哪里結(jié)束十大核心機(jī)制1.確認(rèn)應(yīng)答TCP可靠傳輸?shù)暮诵臋C(jī)制但是在網(wǎng)絡(luò)傳輸?shù)倪^(guò)程中可能會(huì)出現(xiàn) “先發(fā)后至” 的情況比如網(wǎng)絡(luò)卡斷了一下發(fā)送方發(fā)送了倆條信息我這邊可能先收到發(fā)送方最后發(fā)來(lái)的那一條信息然后才收到發(fā)送方最早發(fā)送過(guò)來(lái)的信息這樣信息的含義就可能會(huì)出現(xiàn)錯(cuò)誤~~~此時(shí)TCP報(bào)文段首部格式中有32位序列號(hào)和32位確認(rèn)序列號(hào)32位序列號(hào)針對(duì)傳輸?shù)臄?shù)據(jù)進(jìn)行編號(hào)32位確認(rèn)序列號(hào)給ACK報(bào)文使用關(guān)聯(lián)當(dāng)前這個(gè)ACK是應(yīng)答哪個(gè)數(shù)據(jù)的32為確認(rèn)序列號(hào)有倆種理解方式1.從1001之前的數(shù)據(jù)我已經(jīng)接收到了2.對(duì)方正在想你索要1001之后的數(shù)據(jù)應(yīng)答報(bào)文時(shí)一種特殊的報(bào)文通常沒(méi)有載荷并且在報(bào)頭的標(biāo)志位中將ACK設(shè)置為1總結(jié)一下什么叫做可靠性什么是可靠性 -- 發(fā)送出去的信息發(fā)送方能知道接收方是否接收到了靠什么做到 --- 確認(rèn)應(yīng)答如何實(shí)現(xiàn) --- 發(fā)送方發(fā)送數(shù)據(jù)給接收方接收方接收到數(shù)據(jù)并且返回一個(gè)應(yīng)答報(bào)文可能出現(xiàn)的問(wèn)題 --- 先發(fā)后至如何解決先發(fā)后至問(wèn)題 --- 通過(guò)序列號(hào)和確認(rèn)序列號(hào)解決2.超時(shí)重傳在網(wǎng)絡(luò)傳輸?shù)倪^(guò)程中可能會(huì)出現(xiàn)丟包的概率情況是無(wú)法避免的當(dāng)發(fā)送方發(fā)送一個(gè)數(shù)據(jù)但遲遲沒(méi)有接收到接收方返回的ACK這時(shí)發(fā)送方可能會(huì)意識(shí)到可能是數(shù)據(jù)丟了所以會(huì)選擇在發(fā)送一次數(shù)據(jù)但是如果是ACK丟包了那么也會(huì)導(dǎo)致發(fā)送方發(fā)送倆分同樣的數(shù)據(jù)過(guò)來(lái)這時(shí)如果這倆份數(shù)據(jù)是扣款數(shù)據(jù)難道會(huì)扣款倆次嗎不會(huì)的接收方知道我已經(jīng)接收到的數(shù)據(jù)的序列號(hào)范圍如果發(fā)現(xiàn)新收到的數(shù)據(jù)已經(jīng)在序列號(hào)的范圍內(nèi)說(shuō)明這個(gè)數(shù)據(jù)已經(jīng)接受過(guò)了就會(huì)將重復(fù)的數(shù)據(jù)丟棄所以TCP不僅僅解決了可靠傳輸問(wèn)題還解決了數(shù)據(jù)的傳輸順序問(wèn)題數(shù)據(jù)重復(fù)傳輸?shù)膯?wèn)題但是超時(shí)重傳的重傳也并不是無(wú)限次數(shù)的重傳如果連續(xù)傳輸多次都沒(méi)有達(dá)到對(duì)方說(shuō)明可能出現(xiàn)了非常嚴(yán)重的網(wǎng)絡(luò)故障問(wèn)題從而放棄對(duì)TCP的連接直接將對(duì)方保留的信息刪除因?yàn)榫W(wǎng)絡(luò)故障如果一直重傳也沒(méi)有任何意義沒(méi)必要消耗大量的資源和時(shí)間~~~3.連接管理連接管理分為倆部分1.建立連接三次握手2.斷開(kāi)連接四次揮手這個(gè)核心機(jī)制我會(huì)單獨(dú)出一篇文章講講滴~~~~4.滑動(dòng)窗口提高效率引入滑動(dòng)窗口是為了提高效率因?yàn)門(mén)CP為了確??煽窟B接肯定多多少少會(huì)損失一定的效率滑動(dòng)窗口的本質(zhì)其實(shí)就是批量發(fā)送批量等待ACK窗口大小越大批量傳輸?shù)臄?shù)據(jù)越多整體的傳輸效率越高~~~當(dāng)滑動(dòng)窗口 “丟包” 該如何處理呢ACK丟失的情況就不需要做任何的處理因?yàn)锳CK的確認(rèn)序號(hào)后后一個(gè)ACK可以包含前一個(gè)但是如果是數(shù)據(jù)丟失那么服務(wù)器就會(huì)一直向客戶端索要丟失的數(shù)據(jù)直到客戶端反應(yīng)過(guò)來(lái)然后重新發(fā)送丟失的數(shù)據(jù)服務(wù)器才停止索要要注意服務(wù)器是會(huì)記錄哪些數(shù)據(jù)已經(jīng)接收到了哪些數(shù)據(jù)是丟失的然后就會(huì)一直向客戶端索要丟失了的那段數(shù)據(jù)這個(gè)機(jī)制稱之為快速重傳5.流量控制保證可靠性傳輸當(dāng)滑動(dòng)窗口傳輸?shù)臄?shù)據(jù)越大傳輸?shù)男室簿驮酱笕绻翱谔貏e的大是否可以呢當(dāng)然不行如果傳輸?shù)奶貏e快接收方可能就處理不過(guò)來(lái)就可能照成接收方丟包的情況流量控制就是針對(duì)滑動(dòng)窗口的大小進(jìn)行控制的~~~~???流量控制機(jī)制流量控制是根據(jù)接收方的處理能力來(lái)反向限制發(fā)送方的發(fā)送速度窗口大小1.如何衡量接收方的處理能力根據(jù)緩沖區(qū)剩余空間的大小如果緩沖區(qū)剩余空間還有很多那么發(fā)送方就可以將窗口大小調(diào)大反之就要將窗口大小調(diào)小2.衡量之后如何通知發(fā)送方對(duì)窗口大小做出限制呢把接收方緩沖區(qū)剩余空間大小的值通過(guò)ACK通知發(fā)送給發(fā)送方16位窗口大小就是填寫(xiě)緩沖區(qū)剩余空間大小的值發(fā)送方按照這個(gè)值確定下一輪窗口大小的值該多大如果緩沖區(qū)已經(jīng)滿了那么發(fā)送方就要停止發(fā)送但是如果暫停發(fā)送那么接收方就不會(huì)發(fā)送ACK了嗎那發(fā)送方要如何直到什么時(shí)候可以繼續(xù)發(fā)送數(shù)據(jù)了呢 ------- 發(fā)送方會(huì)時(shí)不時(shí)的發(fā)送一個(gè)窗口探測(cè)詢問(wèn)接收方我可以發(fā)送數(shù)據(jù)了嗎接收方會(huì)根據(jù)緩沖區(qū)剩余空間大小給發(fā)送方返回一個(gè)ACK告訴接收方我緩沖區(qū)剩余空間還有多少如果為0那么就繼續(xù)暫停發(fā)送如果為2000那就可以發(fā)送倆段數(shù)據(jù)過(guò)來(lái)~~~~窗口探測(cè)沒(méi)有載荷只是為了觸發(fā)ACK為了得到新的窗口大小的值6.擁塞控制提高效率擁塞控制和流量控制類(lèi)似都是針對(duì)滑動(dòng)窗口的大小進(jìn)行限制流量控制是針對(duì)接收方緩沖區(qū)剩余空間大小做出限制擁塞控制是針對(duì)通信路徑的處理能力做出限制因?yàn)橥ㄐ怕窂街虚g的狀況是非常復(fù)雜的數(shù)據(jù)都是一點(diǎn)點(diǎn)進(jìn)行嘗試相當(dāng)于我們?nèi)ギ?dāng)一個(gè)陌生的城市城市之間道路非常復(fù)雜我們想去一個(gè)地方只能一點(diǎn)點(diǎn)的嘗試不斷詢問(wèn)路人~~~擁塞控制的機(jī)制剛開(kāi)始發(fā)送數(shù)據(jù)的時(shí)候按照一個(gè)比較小的速度發(fā)送數(shù)據(jù)比較小窗口如果數(shù)據(jù)可以送達(dá)并且沒(méi)有丟包情況那么就加大速度加大窗口大小如果數(shù)據(jù)有丟包情況那么就減小速度減小窗口大小所以窗口的大下并不是一個(gè)固定值而是動(dòng)態(tài)變化的窗口大小最終取決于流量控制和擁塞控制的較小值~~~~~擁塞控制變化規(guī)律圖初始情況下是一個(gè)以非常小的窗口啟動(dòng)慢啟動(dòng)在不丟包的情況下指數(shù)增長(zhǎng)每個(gè)輪次都會(huì)時(shí)窗口大小翻倍增長(zhǎng)當(dāng)窗口大小增長(zhǎng)到了閾值就會(huì)從指數(shù)增長(zhǎng)更改為線性增長(zhǎng)如果增長(zhǎng)的太快下一個(gè)輪次可能會(huì)直接丟包在線性增長(zhǎng)的過(guò)程中如果發(fā)生丟包情況就立即縮小窗口大小縮小窗口大小有倆種方式1.老方式回到 “慢開(kāi)始” 狀態(tài)然后重新指數(shù)增長(zhǎng)然后線性增長(zhǎng)2.新方式回到閾值位置然后線性增長(zhǎng)閾值 丟包時(shí)窗口大小 / 2 7.延時(shí)應(yīng)答提升傳輸效率服務(wù)器并沒(méi)有立即返回客戶端發(fā)送的1-1000的ACK而是等到下一輪數(shù)據(jù)才給客戶端返回2001的ACK此處的延時(shí)應(yīng)答就可以給應(yīng)用程序留更多的處理時(shí)間返回的ACK數(shù)目就可以減少在延時(shí)發(fā)送的這個(gè)時(shí)間段內(nèi)應(yīng)用程序處理的數(shù)據(jù)越多接下來(lái)發(fā)送的數(shù)據(jù)就越快~~~8.)捎帶應(yīng)答配合延時(shí)應(yīng)答當(dāng)客戶端發(fā)送一個(gè)請(qǐng)求服務(wù)器在根據(jù)請(qǐng)求計(jì)算響應(yīng)需要一定的時(shí)間如果計(jì)算的這段時(shí)間剛好遇上了延時(shí)應(yīng)答就會(huì)順便將ACK和響打包成一個(gè)數(shù)據(jù)包然后一起發(fā)送過(guò)去就好比四次揮手也可以是三次揮手如果剛好遇到延時(shí)應(yīng)答就順便將ACK和響應(yīng)打包成一個(gè)數(shù)據(jù)包一并發(fā)送過(guò)去就變成了三次揮手~~~~9.面向字節(jié)流在面向字節(jié)流的過(guò)程中可能會(huì)出現(xiàn)粘包的現(xiàn)象的問(wèn)題在傳輸過(guò)程中每個(gè)數(shù)據(jù)包都是單獨(dú)分開(kāi)的但是當(dāng)數(shù)據(jù)發(fā)送到緩沖區(qū)的時(shí)候就會(huì)出現(xiàn)粘包情況當(dāng)數(shù)據(jù)在緩沖區(qū)的時(shí)候此處在應(yīng)用層上根本區(qū)分不出從哪到哪是一個(gè)完整的應(yīng)用層數(shù)據(jù)包那么該如何解決粘包問(wèn)題呢1.引入分隔符用特殊的符號(hào)作為包的開(kāi)頭和結(jié)束例如使用\n2.在數(shù)據(jù)開(kāi)頭的地方添加一個(gè)固定的屬性說(shuō)明數(shù)據(jù)包的長(zhǎng)度10.異常情況1.進(jìn)程崩潰和四次揮手是完全相同的通過(guò)socket.close觸發(fā)~~~即使進(jìn)程崩潰客戶端沒(méi)了但是TCP的連接還在操作系統(tǒng)內(nèi)核中后續(xù)還是可以處理?yè)]手的情況操作系統(tǒng)會(huì)自動(dòng)對(duì)文件資源進(jìn)行釋放清理PCB的文件描述符表2.主機(jī)關(guān)機(jī)正常關(guān)機(jī)正常的關(guān)機(jī)需要一定的時(shí)間在這段時(shí)間里足夠讓客戶端和服務(wù)器進(jìn)行四次揮手的過(guò)程~~~3.主機(jī)關(guān)機(jī)掉電在這種特殊的情況下程序根本來(lái)不及進(jìn)行四次揮手的操作1.如果是接收方掉電了就不會(huì)給發(fā)送方返回ACK那么發(fā)送方就會(huì)超時(shí)重傳然后通過(guò)幾次超時(shí)重傳發(fā)送方還是接收不到接收方的ACK就會(huì)主動(dòng)放棄鏈接2.如果是發(fā)送方掉電了接收方并不知道發(fā)送方咋回事接收方只能定期給發(fā)送方發(fā)送一個(gè) “心跳包”這個(gè)心跳包不攜帶業(yè)務(wù)只是為了觸發(fā)一次ACK如果發(fā)送方能返回ACK那么接收方就繼續(xù)等待如果接收方發(fā)了心跳包沒(méi)有接收到發(fā)送方返回的ACK此時(shí)接收方就主動(dòng)斷開(kāi)連接~4.網(wǎng)線斷開(kāi)網(wǎng)線斷開(kāi)就是將主動(dòng)關(guān)機(jī)的倆個(gè)機(jī)制結(jié)合起來(lái)接收方周期性發(fā)送心跳包這個(gè)心跳包不攜帶業(yè)務(wù)只為了觸發(fā)一次ACK如果發(fā)送方?jīng)]有給接收方返回ACK接收方就會(huì)主動(dòng)斷開(kāi)連接~~~~發(fā)送方給接收方返回響應(yīng)數(shù)據(jù)如果接收方遲遲沒(méi)有返回ACK就會(huì)觸發(fā)超時(shí)重傳在幾次重傳過(guò)程中還是沒(méi)有接收到接收方的ACK那么發(fā)送方就會(huì)主動(dòng)放棄連接~~~