html商品展示頁(yè)面專(zhuān)業(yè)搜索引擎seo技術(shù)公司
個(gè)人主頁(yè) : 個(gè)人主頁(yè)
個(gè)人專(zhuān)欄 : 《數(shù)據(jù)結(jié)構(gòu)》 《C語(yǔ)言》《C++》《Linux》《網(wǎng)絡(luò)》
文章目錄
- 前言
- 一、TCP協(xié)議格式
- 16位源端口號(hào) 和 16位目的端口號(hào)
- 4位首部長(zhǎng)度
- 16位窗口大小
- 32位序號(hào) 和 32位確認(rèn)序號(hào)
- 6種標(biāo)記位 和 16位緊急指針
- 總結(jié)
前言
本文是我對(duì)于TCP協(xié)議-報(bào)頭字段的知識(shí)總結(jié)
一、TCP協(xié)議格式
16位源端口號(hào) 和 16位目的端口號(hào)
16位源端口號(hào):標(biāo)識(shí)發(fā)送方應(yīng)用程序的端口號(hào),是一個(gè)16位的字段。通過(guò)源端口和目的端口,可以唯一確定一個(gè)TCP連接。
16位目的端口號(hào):標(biāo)識(shí)接收方應(yīng)用程序的端口號(hào),同樣是一個(gè)16位的字段。與源端口一起,用于確定數(shù)據(jù)應(yīng)被哪個(gè)應(yīng)用程序接收。
4位首部長(zhǎng)度
TCP協(xié)議如何解決 報(bào)頭和有效載荷分離的問(wèn)題? 其中 報(bào)頭 為 TCP標(biāo)準(zhǔn)報(bào)頭長(zhǎng)度(20字節(jié)) + 選項(xiàng)。
TCP標(biāo)準(zhǔn)報(bào)頭長(zhǎng)度是固定長(zhǎng)度好分離,但選項(xiàng)的長(zhǎng)度不確定,該怎么辦?
4位首部長(zhǎng)度表示 TCP標(biāo)準(zhǔn)報(bào)頭 + 選項(xiàng) 的大小。
4位首部長(zhǎng)度的取值范圍為[ 0000, 1111 ]轉(zhuǎn)化為10進(jìn)制也就是[ 0, 15 ],那這不還沒(méi)有TCP標(biāo)準(zhǔn)報(bào)頭長(zhǎng)度大嗎?我們還規(guī)定首部長(zhǎng)度的基本單位是4字節(jié),也就說(shuō)4位首部長(zhǎng)度的取值范圍是[ 0, 60 ],選項(xiàng)最多40個(gè)字節(jié)。
現(xiàn)在我們算一下TCP標(biāo)準(zhǔn)報(bào)頭的4位首部長(zhǎng)度,TCP標(biāo)準(zhǔn)報(bào)頭是20字節(jié),那4位首部長(zhǎng)度是5,轉(zhuǎn)化為2進(jìn)制就是0101 。
注意:TCP的報(bào)頭長(zhǎng)度必須是4的整數(shù)倍,因?yàn)榛締挝皇?字節(jié)。
16位窗口大小
- 16位窗口大小:表示接收方愿意并能夠接收多少數(shù)據(jù)。用于實(shí)現(xiàn)TCP的流量控制機(jī)制。
那我們?nèi)绾卫斫?6位窗口大小?我們先看下圖。
我們都知道,TCP具有發(fā)送和接受緩沖區(qū),即TCP是全雙工通信。發(fā)送數(shù)據(jù)就是把數(shù)據(jù)拷貝到操作系統(tǒng)內(nèi)的發(fā)送緩沖區(qū),再?gòu)陌l(fā)送緩沖區(qū)到接收方的接受緩沖區(qū)。
那如果發(fā)送方一直瘋狂的向接收方發(fā)送數(shù)據(jù),此時(shí)發(fā)送方不清楚接收方的接受能力(接受緩沖區(qū)的剩余空間大小為接受能力),發(fā)送方發(fā)送數(shù)據(jù)太快,導(dǎo)致接收方來(lái)不及接受數(shù)據(jù),接收方的接受緩沖區(qū)滿了。發(fā)送方還是發(fā)送數(shù)據(jù),那接收方接受到數(shù)據(jù),就會(huì)直接丟棄。雖然TCP有重傳機(jī)制,可以重新發(fā)送數(shù)據(jù),保證可靠性。但這不合理且不高效,數(shù)據(jù)千辛萬(wàn)苦從網(wǎng)絡(luò)到接收方,接收方卻直接丟棄了。
那要如何使這樣的情況合理?如果接收方來(lái)不及接受數(shù)據(jù)了,發(fā)送方就慢點(diǎn)發(fā),甚至等會(huì)再發(fā)。我們把這種如果對(duì)方來(lái)不及接受,就要求發(fā)送方發(fā)送變慢,甚至停止發(fā)送的策略,叫做流量控制。
對(duì)于流量控制的前提是:發(fā)送方可以知道接收方的接受能力。那發(fā)送方有如何知道接收方的接受能力呢?
這就要先簡(jiǎn)單的看看確認(rèn)應(yīng)答機(jī)制了。如 client給server發(fā)送一條消息,TCP為了保證可靠性,要求接收方對(duì)發(fā)送方發(fā)過(guò)來(lái)的消息進(jìn)行確認(rèn),即只要client收到server發(fā)送的確認(rèn),client就會(huì)認(rèn)為server收到 “hello” 這條消息,保證client 到 server 的可靠性。
要注意其中"hello"這條消息是TCP報(bào)文。
現(xiàn)在發(fā)送方每發(fā)送一條消息,都會(huì)收到接收方的應(yīng)答消息。那么發(fā)送方就可以從應(yīng)答消息中的16位窗口大小來(lái)判斷,接收方的接受能力,從而避免發(fā)送方發(fā)送的數(shù)據(jù)因?yàn)榻邮辗骄彌_區(qū)滿了,而直接丟棄的問(wèn)題。
注意:16位窗口大小,是指自身的接受緩沖區(qū)中剩余空間的大小。
32位序號(hào) 和 32位確認(rèn)序號(hào)
我們先來(lái)看兩種TCP發(fā)送數(shù)據(jù)的方式:
先看串行發(fā)送,client每發(fā)送一條數(shù)據(jù)后,必須得到server發(fā)送的ACK,才能繼續(xù)發(fā)送數(shù)據(jù)。這樣client可以清晰的知道每個(gè)ACK對(duì)應(yīng)的是那條數(shù)據(jù)。這樣雖然保證了可靠性,但效率低。
再看并行發(fā)送,client可以一次發(fā)送多條數(shù)據(jù),那么server也要發(fā)送對(duì)應(yīng)數(shù)量的應(yīng)答給client(原則上要求server對(duì)每一條消息做出應(yīng)答)。這樣client發(fā)送時(shí)間,進(jìn)行了重疊,效率得到提升。但這也引來(lái)了幾個(gè)問(wèn)題。
- client怎么知道那個(gè)ACK是哪個(gè)發(fā)送數(shù)據(jù)的應(yīng)答?如果client接受到的ACK與發(fā)送數(shù)據(jù)數(shù)量相同,那至少表明client發(fā)送的數(shù)據(jù),server都收到了。但如果client收到的ACK數(shù)量少于發(fā)送數(shù)據(jù)的數(shù)量呢?此時(shí)client就不清楚那個(gè)發(fā)送數(shù)據(jù)沒(méi)有被server接受到。
- 因?yàn)榫W(wǎng)絡(luò)環(huán)境復(fù)雜,server接受到數(shù)據(jù)的順序不一定是按照client發(fā)送數(shù)據(jù)的順序。此時(shí),如果client把報(bào)文分兩次發(fā)送,server就有可能先收到數(shù)據(jù),再收到報(bào)頭;這就不可靠了。
對(duì)于上面兩個(gè)問(wèn)題,我們可以對(duì)發(fā)送的數(shù)據(jù) 和 ACK 進(jìn)行編號(hào)。
此時(shí)client就可以根據(jù)每個(gè)ACK的編號(hào),來(lái)確定哪個(gè)發(fā)送數(shù)據(jù)被server接受到了。而server也可以根據(jù)發(fā)送數(shù)據(jù)的序號(hào),進(jìn)行排序,從而保證數(shù)據(jù)的按序到達(dá)。
上面的序號(hào)就是 32位序號(hào) 和 32位確認(rèn)序號(hào)。
- 32位序號(hào):用于對(duì)TCP報(bào)文段進(jìn)行編號(hào)和排序。每個(gè)TCP報(bào)文段都有一個(gè)唯一的序列號(hào),確保數(shù)據(jù)的唯一性和可識(shí)別性。
- 32位確認(rèn)序號(hào):用于標(biāo)識(shí)接收端確認(rèn)收到的數(shù)據(jù)段。它是成功收到的數(shù)據(jù)序列號(hào)加1,表示接收端已經(jīng)成功接收了序列號(hào)小于該確認(rèn)序號(hào)的所有數(shù)據(jù)。
注意:32位確認(rèn)序號(hào)還表示,確認(rèn)序號(hào)之前的所有的報(bào)文已經(jīng)被對(duì)方全部收到了。為什么要這樣規(guī)定?允許少量報(bào)文的丟失,提高了效率。
如上圖,如果server發(fā)送的3個(gè)ACK,只有序號(hào)為301的ACK被client接受到了,那client就會(huì)認(rèn)為發(fā)送的3條數(shù)據(jù)都被server接受到了,效率提升了。
那這里,我們可能會(huì)有一個(gè)問(wèn)題?32位序號(hào) 和 32位確認(rèn)序號(hào) 可以同一個(gè)字段嗎?答案是不能。
向上圖,client 和 server互相發(fā)送信息。在情況1 server對(duì)client的回應(yīng)是發(fā)送兩條信息,那server可不可以將這兩條信息作為一條信息發(fā)送?要知道發(fā)送的消息都是完整的TCP報(bào)文,而ACK只是一個(gè)ACK標(biāo)志位置1的報(bào)頭,那將報(bào)頭和 “hello” 數(shù)據(jù)合并不也是一個(gè)完整報(bào)文嗎?這樣不僅對(duì)client發(fā)送的"hello"進(jìn)行了應(yīng)答,而且還對(duì)client的信息進(jìn)行了回復(fù)。這些效率進(jìn)行了提升。像這樣報(bào)文大都既是數(shù)據(jù)(需要32位序號(hào),保證按序到達(dá)),又是對(duì)歷史報(bào)文的確認(rèn)(需要32位確認(rèn)序號(hào)),32位序號(hào) 和 32位確認(rèn)序號(hào) 同事使用,不能是同一個(gè)字段。
6種標(biāo)記位 和 16位緊急指針
我們知道一個(gè)server會(huì)被多個(gè)client連接,這么多連接,總會(huì)有不同的鏈接請(qǐng)求。
即server一定會(huì)同時(shí)收到各種各樣不同類(lèi)型的TCP報(bào)文,也就表示報(bào)文要有類(lèi)型,如何表示報(bào)文的類(lèi)型?TCP中是6種標(biāo)記位來(lái)表示報(bào)文類(lèi)型。
- URG:緊急指針是否有效
- ACK:確認(rèn)序號(hào)是否有效
- PSH:提示接收端應(yīng)用程序立刻從TCP緩沖區(qū)把數(shù)據(jù)讀走
- RST:對(duì)方要求重新建立連接,我們把攜帶RST標(biāo)識(shí)的稱(chēng)為復(fù)位報(bào)文段
- SYN:請(qǐng)求建立連接;我們把攜帶SYN標(biāo)識(shí)的稱(chēng)為同步報(bào)文段
- FIN:通知對(duì)方,本端要關(guān)閉了,我們稱(chēng)攜帶FIN標(biāo)識(shí)的為結(jié)束報(bào)文段
這里我們介紹URG,PSH,RST。
URG 和 16位緊急指針
在client 和 server 雙方通訊時(shí),TCP報(bào)文要按照32位序號(hào)排序,按序處理,也就是排隊(duì)。如果此時(shí) 服務(wù)器通訊雙方有一些緊急數(shù)據(jù)時(shí),因?yàn)門(mén)CP報(bào)文是有序號(hào)的,那該緊急數(shù)據(jù)也要按序處理嗎?這就不好了,我們應(yīng)該盡快處理緊急數(shù)據(jù),即該報(bào)文要提前處理,也就是要插隊(duì)。
此時(shí),我們就需要 URG 和 16位緊急指針。
- URG標(biāo)記位被置 1 ,表示該報(bào)文是緊急報(bào)文
- 16位緊急指針表示,在當(dāng)前報(bào)文中,緊急數(shù)據(jù)在有效載荷中的偏移量
注意:只有URG無(wú)效,16位緊急指針也就無(wú)效;只有URG被置1,16位緊急指針也要被查看
這就有一個(gè)問(wèn)題。緊急數(shù)據(jù)的大小是多少?畢竟16位緊急指針只是給了一個(gè)地址,并沒(méi)有給緊急數(shù)據(jù)有多少個(gè)字節(jié)。答案是 1個(gè)字節(jié)。
緊急任務(wù)都有哪些?
PSH
當(dāng)client 給 server 發(fā)送 “hello” 時(shí),server要給 client 發(fā)送 ACK;但不僅僅只發(fā)送 ACK 還會(huì)同步 窗口大小。比較發(fā)送的是一個(gè)完整報(bào)文。
如果server因?yàn)樯蠈觝ttp 處理一個(gè)比較耗時(shí)的任務(wù),導(dǎo)致進(jìn)程卡主了。client 給 server 發(fā)送 “hello”, server 給 client 發(fā)送 ACK ,同時(shí)更新窗口大小為 0;
此時(shí)表示,server的接受緩沖區(qū)滿了,client知道不能發(fā)送消息了,只能等待。那以后client 如何知道 server 緩沖區(qū)的情況,這會(huì)不會(huì)出現(xiàn)雙方互相等待的情況?
并不會(huì),此時(shí)client會(huì)定期向server發(fā)送詢(xún)問(wèn)報(bào)文(只有報(bào)頭),根據(jù)TCP的確認(rèn)應(yīng)答機(jī)制,server要給client發(fā)送ACK(攜帶了server的窗口大小)。同時(shí) 當(dāng)上層將接受緩沖區(qū)的數(shù)據(jù)取走,也就是server接受緩沖區(qū)的剩余空間 從 0 變?yōu)?非0。server 會(huì)主動(dòng)給client發(fā)送窗口大小更新報(bào)文。
上面兩種策略同時(shí)使用,那種方式先被client收到,client就會(huì)繼續(xù)發(fā)送信息。
其中,client發(fā)送的詢(xún)問(wèn)報(bào)文,就是一個(gè)PSH標(biāo)記位被置1的報(bào)頭。
注意:PSH不僅僅使用在上述場(chǎng)景中,在所有數(shù)據(jù)需要盡快交付的場(chǎng)景下,都可以使用。如Linux的指令輸入
RST
我們知道TCP通訊的前提,必須進(jìn)行三次握手。這里有個(gè)問(wèn)題,TCP是保證可靠性的,那是不是三次握手必須成功?不是,三次握手可能失敗。那TCP保證可考性是怎么回事,該可靠性不是保證數(shù)據(jù)100%發(fā)送到,而是數(shù)據(jù)被接收方收到,發(fā)送方要知道;數(shù)據(jù)發(fā)送出現(xiàn)問(wèn)題,發(fā)送方也要知道。
現(xiàn)在我們以三次握手出現(xiàn)問(wèn)題為例,介紹RST出現(xiàn)場(chǎng)景。
我們先要知道對(duì)于client 和 server 來(lái)說(shuō), 什么時(shí)候,連接建立好了。
- 對(duì)于client,是發(fā)出ACK就認(rèn)為連接建立好了
- 對(duì)于server,是要收到client發(fā)送的ACK,才認(rèn)為連接建立好了
注意:這里client 和 server 認(rèn)為建立好鏈接有一定的時(shí)間差
了解上面這點(diǎn),我們?cè)偻驴?。其中SYN 和 SYN + ACK 如果丟包,我們不擔(dān)心。因?yàn)镾YN 和 SYN + ACK都有對(duì)應(yīng)的應(yīng)答,但 ACK 如果丟失,就不好辦了。如果client發(fā)送的ACK丟包了,但client認(rèn)為T(mén)CP連接已經(jīng)建立好了,而server因?yàn)檫€沒(méi)有收到client的ACK,認(rèn)為還沒(méi)有建立TCP鏈接。這就存在了 連接建立認(rèn)知不一致 。此時(shí)client給server發(fā)送數(shù)據(jù),server會(huì)給client發(fā)送一個(gè)重新建立鏈接的報(bào)文(RST標(biāo)記位被置1 的報(bào)文),此時(shí)client會(huì)知道發(fā)送的ACK丟包了,會(huì)重新建立鏈接。
還有很多其它例子。
下圖就是linux-2.6.11.10中tcp的報(bào)頭字段
總結(jié)
TCP保證可靠性,但又不僅僅保證可靠性,還會(huì)進(jìn)行各種提高效率的設(shè)定。
以上就是我對(duì)于TCP協(xié)議的知識(shí)總結(jié)