這一篇TCP總結(jié)請(qǐng)收下

前言

很高興遇見你~

TCP這些東西,基本每個(gè)程序猿都或多或少是掌握的了。雖然感覺在實(shí)際開發(fā)中沒有什么用武之處,但,面試他要問(wèn)啊

image

而最近大家伙過(guò)完年,也都在準(zhǔn)備春招,我也一樣。閱讀了一些okHttp源碼之后,又屁顛屁顛地跑回來(lái)重新把tcp、http這些東西給重新學(xué)了一遍。okHttp基本都是這些協(xié)議的實(shí)現(xiàn),而理解源碼的基礎(chǔ)是,理解tcp、http。

重新看了一遍tcp之后,我把這些東西給總結(jié)了下來(lái),也就有了這篇文章。

計(jì)算機(jī)網(wǎng)絡(luò)的知識(shí)特點(diǎn)就是:瑣碎??勘痴b“面試八股文”估計(jì)沒多久就忘了。TCP是計(jì)算機(jī)網(wǎng)絡(luò)運(yùn)輸層的一個(gè)協(xié)議,所以首先要對(duì)計(jì)網(wǎng)分層結(jié)構(gòu)以及運(yùn)輸層有一定的理解。然后是TCP的四個(gè)重點(diǎn):面向連接、可靠傳輸原理、流量控制和擁塞控制,最后再補(bǔ)充一點(diǎn)粘包和拆包的知識(shí)。

計(jì)網(wǎng)分層結(jié)構(gòu)

考慮最簡(jiǎn)單的情況:兩臺(tái)主機(jī)之間的通信。這個(gè)時(shí)候只需要一條網(wǎng)線把兩者連起來(lái),規(guī)定好彼此的硬件接口,如都用USB、電壓10v、頻率2.4GHz等,這一層就是物理層,這些規(guī)定就是物理層協(xié)議 。

image

我們當(dāng)然不滿足于只有兩臺(tái)電腦連接,因此我們可以使用交換機(jī)把多個(gè)電腦連接起來(lái),如下圖:

image.png

這樣連接起來(lái)的網(wǎng)絡(luò),稱為局域網(wǎng),也可以稱為以太網(wǎng)(以太網(wǎng)是局域網(wǎng)的一種)。在這個(gè)網(wǎng)絡(luò)中,我們需要標(biāo)識(shí)每個(gè)機(jī)器,這樣才可以指定要和哪個(gè)機(jī)器通信。這個(gè)標(biāo)識(shí)就是硬件地址MAC。硬件地址隨機(jī)器的生產(chǎn)就被確定,永久性唯一。在局域網(wǎng)中,我們需要和另外的機(jī)器通信時(shí),只需要知道他的硬件地址,交換機(jī)就會(huì)把我們的消息發(fā)送到對(duì)應(yīng)的機(jī)器。

這里我們可以不管底層的網(wǎng)線接口如何發(fā)送,把物理層抽離,在他之上創(chuàng)建一個(gè)新的層次,這就是數(shù)據(jù)鏈路層


我們依然不滿足于局域網(wǎng)的規(guī)模,需要把所有的局域網(wǎng)聯(lián)系起來(lái),這個(gè)時(shí)候就需要用到路由器來(lái)連接兩個(gè)局域網(wǎng):

image.png

但是如果我們還是使用硬件地址來(lái)作為通信對(duì)象的唯一標(biāo)識(shí),那么當(dāng)網(wǎng)絡(luò)規(guī)模越來(lái)越大,需要記住所有機(jī)器的硬件地址是不現(xiàn)實(shí)的;同時(shí),一個(gè)網(wǎng)絡(luò)對(duì)象可能會(huì)頻繁更換設(shè)備,這個(gè)時(shí)候硬件地址表維護(hù)起來(lái)更加復(fù)雜。這里使用了一個(gè)新的地址來(lái)標(biāo)記一個(gè)網(wǎng)絡(luò)對(duì)象:IP地址 。

通過(guò)一個(gè)簡(jiǎn)單的寄信例子來(lái)理解IP地址。

我住在北京市,我朋友A住在上海市,我要給朋友A寫信:

  1. 寫完信,我會(huì)在信上寫好我朋友A的地址,并放到北京市郵局(給信息附加目標(biāo)IP地址,并發(fā)送給路由器)
  2. 郵局會(huì)幫我把信運(yùn)輸?shù)缴虾J挟?dāng)?shù)剜]局(信息會(huì)經(jīng)過(guò)路由傳遞到目標(biāo)IP局域網(wǎng)的路由器)
  3. 上海市當(dāng)?shù)芈酚善鲿?huì)幫我把信交給朋友A(局域網(wǎng)內(nèi)通信)

因此,這里IP地址就是一個(gè)網(wǎng)絡(luò)接入地址(朋友A的住址),我只需要知道目標(biāo)IP地址,路由器就可以把消息給我?guī)У健?strong>在局域網(wǎng)中,就可以動(dòng)態(tài)維護(hù)一個(gè)MAC地址與IP地址的映射關(guān)系,根據(jù)目的IP地址就可以尋找到機(jī)器的MAC地址進(jìn)行發(fā)送 。

這樣我們不需管理底層如何去選擇機(jī)器,我們只需要知道IP地址,就可以和我們的目標(biāo)進(jìn)行通信。這一層就是網(wǎng)絡(luò)層。網(wǎng)絡(luò)層的核心作用就是 提供主機(jī)之間的邏輯通信 。這樣,在網(wǎng)絡(luò)中的所有主機(jī),在邏輯上都連接起來(lái)了,上層只需要提供目標(biāo)IP地址和數(shù)據(jù),網(wǎng)絡(luò)層就可以把消息發(fā)送到對(duì)應(yīng)的主機(jī)。


一個(gè)主機(jī)有多個(gè)進(jìn)程,進(jìn)程之間進(jìn)行不同的網(wǎng)絡(luò)通信,如邊和朋友開黑邊和女朋友聊微信。我的手機(jī)同時(shí)和兩個(gè)不同機(jī)器進(jìn)行通信。那么當(dāng)我的手機(jī)收到數(shù)據(jù)時(shí),如何區(qū)分是微信的數(shù)據(jù),還是王者的數(shù)據(jù)?那么就必須在網(wǎng)絡(luò)層之上再添加一層:運(yùn)輸層

image

運(yùn)輸層通過(guò)socket(套接字),將網(wǎng)絡(luò)信息進(jìn)行進(jìn)一步的拆分,不同的應(yīng)用進(jìn)程可以獨(dú)立進(jìn)行網(wǎng)絡(luò)請(qǐng)求,互不干擾。這就是運(yùn)輸層的最本質(zhì)特點(diǎn):提供進(jìn)程之間的邏輯通信 。這里的進(jìn)程可以是主機(jī)之間,也可以是同個(gè)主機(jī),所以在android中,socket通信也是進(jìn)程通信的一種方式。


現(xiàn)在不同的機(jī)器上的應(yīng)用進(jìn)程之間可以獨(dú)立通信了,那么我們就可以在計(jì)算機(jī)網(wǎng)絡(luò)上開發(fā)出形形式式的應(yīng)用:如web網(wǎng)頁(yè)的http,文件傳輸ftp等等。這一層稱為應(yīng)用層。

應(yīng)用層還可以進(jìn)一步拆分出表示層、會(huì)話層,但他們的本質(zhì)特點(diǎn)都沒有改變:完成具體的業(yè)務(wù)需求 。和下面的四層相比,他們并不是必須的,可以歸屬到應(yīng)用層中。


最后對(duì)計(jì)網(wǎng)分層進(jìn)行小結(jié):

image.png
  1. 最底層物理層,負(fù)責(zé)兩個(gè)機(jī)器之間通過(guò)硬件的直接通信;
  2. 數(shù)據(jù)鏈路層使用硬件地址在局域網(wǎng)中進(jìn)行尋址,實(shí)現(xiàn)局域網(wǎng)通信;
  3. 網(wǎng)絡(luò)層通過(guò)抽象IP地址實(shí)現(xiàn)主機(jī)之間的邏輯通信;
  4. 運(yùn)輸層在網(wǎng)絡(luò)層的基礎(chǔ)上,對(duì)數(shù)據(jù)進(jìn)行拆分,實(shí)現(xiàn)應(yīng)用進(jìn)程的獨(dú)立網(wǎng)絡(luò)通信;
  5. 應(yīng)用層在運(yùn)輸層的基礎(chǔ)上,根據(jù)具體的需求開發(fā)形形式式的功能。

這里需要注意的是,分層并不是在物理上的分層,而是邏輯上的分層。通過(guò)對(duì)底層邏輯的封裝,使得上層的開發(fā)可以直接依賴底層的功能而無(wú)需理會(huì)具體的實(shí)現(xiàn),簡(jiǎn)便了開發(fā)。

這種分層的思路,也就是責(zé)任鏈設(shè)計(jì)模式,通過(guò)層層封裝,把不同的職責(zé)獨(dú)立起來(lái),更加方便開發(fā)、維護(hù)等等。okHttp中的攔截器設(shè)計(jì)模式,也是這種責(zé)任鏈模式。

運(yùn)輸層

本文主要是講解TCP,這里需要增加一些運(yùn)輸層的知識(shí)。

本質(zhì):提供進(jìn)程通信

yqs3gx.md.png

在運(yùn)輸層之下的網(wǎng)絡(luò)層,是不知道該數(shù)據(jù)包屬于哪個(gè)進(jìn)程,他只負(fù)責(zé)數(shù)據(jù)包的接收與發(fā)送。運(yùn)輸層則負(fù)責(zé)接收不同進(jìn)程的數(shù)據(jù)交給網(wǎng)絡(luò)層,同時(shí)把網(wǎng)絡(luò)層的數(shù)據(jù)拆分交給不同的進(jìn)程。從上往下匯聚到網(wǎng)絡(luò)層,稱為多路復(fù)用,從下往上拆分,稱為多路拆分 。

運(yùn)輸層的表現(xiàn),受網(wǎng)絡(luò)層的限制。這很好理解,網(wǎng)絡(luò)層是運(yùn)輸層的底層支持。所以運(yùn)輸層是無(wú)法決定自己帶寬、時(shí)延等的上限。但可以基于網(wǎng)絡(luò)層開發(fā)更多的特性:如可靠傳輸。網(wǎng)絡(luò)層只負(fù)責(zé)盡力把數(shù)據(jù)包從一端發(fā)送到另一端,而不保證數(shù)據(jù)可以到達(dá)且完整。

底層實(shí)現(xiàn):socket

前面講到,最簡(jiǎn)單的運(yùn)輸層協(xié)議,就是提供進(jìn)程之間的獨(dú)立通信 ,但底層的實(shí)現(xiàn),是socket之間的獨(dú)立通信 。在網(wǎng)絡(luò)層中,IP地址是一個(gè)主機(jī)邏輯地址,而在運(yùn)輸層中,socket是一個(gè)進(jìn)程的邏輯地址;當(dāng)然,一個(gè)進(jìn)程可以擁有多個(gè)socket。應(yīng)用進(jìn)程可以通過(guò)監(jiān)聽socket,來(lái)獲取這個(gè)socket接受到的消息。

舉個(gè)例子來(lái)理解socket。如下圖

image

每一個(gè)主機(jī)可以創(chuàng)建很多個(gè)socket來(lái)接收信息。如主機(jī)A的微信進(jìn)程,想要發(fā)送給主機(jī)B的微信,那么他只需要發(fā)送給主機(jī)B的socketC,主機(jī)B的微信就會(huì)從socketC中取到消息。(當(dāng)然實(shí)際的流程不是這樣的,我們的消息需要經(jīng)過(guò)微信后臺(tái)服務(wù)器,這里只是舉例子)

同理,主機(jī)B的QQ,想要發(fā)送消息給主機(jī)A的QQ,那么只需要把消息發(fā)送給socketB,主機(jī)A的QQ就可以拿到消息了。

socket并不是一個(gè)實(shí)實(shí)在在的東西,而是運(yùn)輸層抽象出來(lái)的一個(gè)對(duì)象。運(yùn)輸層增加了端口這個(gè)概念,來(lái)區(qū)分不同的socket。端口可以理解為一個(gè)主機(jī)上有很多的網(wǎng)絡(luò)通信口,每個(gè)端口都有一個(gè)端口號(hào),端口的數(shù)量由運(yùn)輸層協(xié)議確定。

不同的運(yùn)輸層協(xié)議對(duì)socket有不同的定義方式。在UDP協(xié)議中,使用目標(biāo)IP+目標(biāo)端口號(hào)來(lái)定義一個(gè)socket;在TCP中使用目標(biāo)IP+目標(biāo)端口號(hào)+源IP+源端口號(hào)來(lái)定義一個(gè)socket。我們只需要在運(yùn)輸層報(bào)文的頭部附加上這些信息,目標(biāo)主機(jī)就會(huì)知道我們要發(fā)送給哪個(gè)socket,對(duì)應(yīng)監(jiān)聽該socket的進(jìn)程就可獲得信息。

運(yùn)輸層協(xié)議

運(yùn)輸層的協(xié)議就是大名鼎鼎的TCP和UDP。其中,UDP是最精簡(jiǎn)的運(yùn)輸層協(xié)議,只實(shí)現(xiàn)了進(jìn)程間的通信;而TCP在UDP的基礎(chǔ)上,實(shí)現(xiàn)了可靠傳輸、流量控制、擁塞控制、面向連接等等特性,同時(shí)也更加復(fù)雜。

當(dāng)然除此之外,還有更多更優(yōu)秀的運(yùn)輸層協(xié)議,但目前廣為使用的,就是TCP和UDP。UDP在后面也會(huì)總結(jié)到。

TCP協(xié)議首部

TCP協(xié)議,表現(xiàn)在報(bào)文上,就是會(huì)在應(yīng)用層傳輸下來(lái)的數(shù)據(jù)前附加上一個(gè)TCP首部,這個(gè)首部附加了TCP信息,先來(lái)整體看一下這個(gè)首部的結(jié)構(gòu):

image

這張圖是來(lái)自我大學(xué)老師的課件, 非常好用,所以一直拿來(lái)學(xué)習(xí)。最下面部分表示了報(bào)文之間的關(guān)系,TCP數(shù)據(jù)部分就是應(yīng)用層傳下來(lái)的數(shù)據(jù)。

TCP首部固定長(zhǎng)度是20字節(jié),下面還有4字節(jié)是可選的。內(nèi)容很多,但其中有一些我們比較熟悉的:源端口,目標(biāo)端口。嗯?socket不是還需要IP進(jìn)行定位嗎?IP地址在網(wǎng)絡(luò)層被附加了。其他的內(nèi)容后面都會(huì)慢慢講解,作為一篇總結(jié)文章,這里放出查閱表,方便復(fù)習(xí):

頭部參數(shù) 字節(jié)數(shù) 作用
源端口和目的端口字段 各占兩字節(jié) socket是通過(guò)端口號(hào)和IP號(hào)來(lái)進(jìn)行定義,這里表示發(fā)出消息的主機(jī)端口以及接收消息的目標(biāo)主機(jī)端口
序號(hào)字段 4 字節(jié) TCP 連接中傳送的數(shù)據(jù)流中的每一個(gè)字節(jié)都編上一個(gè)序號(hào)。序號(hào)字段的值則指的是本報(bào)文段所發(fā)送的數(shù)據(jù)的第一個(gè)字節(jié)的序號(hào)。長(zhǎng)度4字節(jié),所以序號(hào)的范圍是【0,2^32 - 1】
確認(rèn)號(hào)字段 4字節(jié) 是期望收到對(duì)方的下一個(gè)報(bào)文段的數(shù)據(jù)的第一個(gè)字節(jié)的序號(hào)。
數(shù)據(jù)偏移(即首部長(zhǎng)度) 4位 指出 TCP 報(bào)文段的數(shù)據(jù)起始處距離 TCP 報(bào)文段的起始處有多遠(yuǎn)?!皵?shù)據(jù)偏移”的單位是 32 位(以 4 字節(jié)為計(jì)算單位)
保留字段 6位 保留為今后使用,但目前應(yīng)置為 0
緊急 URG 1位 當(dāng) URG =1 時(shí),表明緊急指針字段有效。它告訴系統(tǒng)此報(bào)文段中有緊急數(shù)據(jù),應(yīng)盡快傳送(相當(dāng)于高優(yōu)先級(jí)的數(shù)據(jù))
確認(rèn) ACK 1位 只有當(dāng) ACK=1 時(shí)確認(rèn)號(hào)字段才有效。當(dāng) ACK = 0 時(shí),確認(rèn)號(hào)無(wú)效。當(dāng)收到報(bào)文需要向發(fā)送方發(fā)送確認(rèn)報(bào)時(shí)設(shè)置該標(biāo)志位為1。
推送 PSH 1位 接收 TCP 收到 PSH = 1 的報(bào)文段,就盡快地交付接收應(yīng)用進(jìn)程,而不再等到整個(gè)緩存都填滿了后再向上交付。
復(fù)位 RST 1位 當(dāng) RST =1 時(shí),表明 TCP 連接中出現(xiàn)嚴(yán)重差錯(cuò)(如由于主機(jī)崩潰或其他原因),必須釋放連接,然后再重新建立運(yùn)輸連接。
同步 SYN 1位 同步 SYN = 1 表示這是一個(gè)連接請(qǐng)求或連接接受報(bào)文。
終止 FIN 1位 用來(lái)釋放一個(gè)連接。FIN = 1 表明此報(bào)文段的發(fā)送端的數(shù)據(jù)已發(fā)送完畢,并要求釋放運(yùn)輸連接
窗口字段 2字節(jié) 發(fā)送方接收緩存區(qū)剩下的字節(jié) 數(shù),注意單位是字節(jié)。
檢驗(yàn)和 2字節(jié) 檢驗(yàn)和字段檢驗(yàn)的范圍包括首部和數(shù)據(jù)這兩部分。在計(jì)算檢驗(yàn)和時(shí),要在 TCP 報(bào)文段的前面加上 12 字節(jié)的偽首部。主要是檢驗(yàn)報(bào)文是否發(fā)生了錯(cuò)誤,如某個(gè)‘1’變成了‘0’。
緊急指針字段 2字節(jié) 指出在本報(bào)文段中緊急數(shù)據(jù)共有多少個(gè)字節(jié)(緊急數(shù)據(jù)放在本報(bào)文段數(shù)據(jù)的最前面)
選項(xiàng)字段 長(zhǎng)度不定 TCP 最初只規(guī)定了一種選項(xiàng),即最大報(bào)文段長(zhǎng)度 MSS。MSS 告訴對(duì)方 TCP:“我的緩存所能接收的報(bào)文段的數(shù)據(jù)字段的最大長(zhǎng)度是 MSS 個(gè)字節(jié)。”
填充字段 不定 這是為了使整個(gè)首部長(zhǎng)度是 4 字節(jié)的整數(shù)倍。

選項(xiàng)字段中包含以下其他選項(xiàng):

選項(xiàng) 作用
窗口擴(kuò)大選項(xiàng) 占 3 字節(jié),其中有一個(gè)字節(jié)表示移位值 S。新的窗口值等于 TCP 首部中的窗口位數(shù)增大到 (16 + S),相當(dāng)于把窗口值向左移動(dòng) S 位后獲得實(shí)際的窗口大小
時(shí)間戳選項(xiàng) 占 10 字節(jié),其中最主要的字段時(shí)間戳值字段(4 字節(jié))和時(shí)間戳回送回答字段(4 字節(jié)),主要是用于計(jì)算數(shù)據(jù)報(bào)在網(wǎng)絡(luò)中傳輸?shù)耐禃r(shí)間。
選擇確認(rèn)選項(xiàng) 接收方收到了和前面的字節(jié)流不連續(xù)的兩個(gè)字節(jié)塊,需要告訴發(fā)送方目前已經(jīng)接收到的數(shù)據(jù)報(bào)范圍。每一個(gè)段需要兩個(gè)邊界,一個(gè)邊界需要4字節(jié)來(lái)表示,選項(xiàng)字段最長(zhǎng)是40字節(jié),所以最多可以表示4個(gè)已接收的字段。

講完下面內(nèi)容,再回來(lái)看這些字段就熟悉了。

TCP面向字節(jié)流特性

TCP并不是把應(yīng)用層傳輸過(guò)來(lái)的數(shù)據(jù)直接加上首部然后發(fā)送給目標(biāo),而是把數(shù)據(jù)看成一個(gè)字節(jié) 流,給他們標(biāo)上序號(hào)之后分部分發(fā)送。這就是TCP的 面向字節(jié)流 特性:

image
  • TCP會(huì)以流的形式從應(yīng)用層讀取數(shù)據(jù)并存放在自己的發(fā)送緩存區(qū)中,同時(shí)為這些字節(jié)標(biāo)上序號(hào)
  • TCP會(huì)從發(fā)送方緩沖區(qū)選擇適量的字節(jié)組成TCP報(bào)文,通過(guò)網(wǎng)絡(luò)層發(fā)送給目標(biāo)
  • 目標(biāo)會(huì)讀取字節(jié)并存放在自己的接收方緩沖區(qū)中,并在合適的時(shí)候交付給應(yīng)用層

面向字節(jié)流的好處是無(wú)需一次存儲(chǔ)過(guò)大的數(shù)據(jù)占用太多內(nèi)存,壞處是無(wú)法知道這些字節(jié)代表的意義,例如應(yīng)用層發(fā)送一個(gè)音頻文件和一個(gè)文本文件,對(duì)于TCP來(lái)說(shuō)就是一串字節(jié)流,沒有意義可言,這會(huì)導(dǎo)致粘包以及拆包問(wèn)題,后面講。

可靠傳輸原理

前面講到,TCP是可靠傳輸協(xié)議,也就是,一個(gè)數(shù)據(jù)交給他,他肯定可以完整無(wú)誤地發(fā)送到目標(biāo)地址,除非網(wǎng)絡(luò)炸了。他實(shí)現(xiàn)的網(wǎng)絡(luò)模型如下:

image

對(duì)于應(yīng)用層來(lái)說(shuō),他就是一個(gè)可靠傳輸?shù)牡讓又С址?wù);而運(yùn)輸層底層采用了網(wǎng)絡(luò)層的不可靠傳輸。雖然在網(wǎng)絡(luò)層甚至數(shù)據(jù)鏈路層就可以使用協(xié)議來(lái)保證數(shù)據(jù)傳輸?shù)目煽啃?,但這樣網(wǎng)絡(luò)的設(shè)計(jì)會(huì)更加復(fù)雜、效率會(huì)隨之降低。把數(shù)據(jù)傳輸?shù)目煽啃员WC放在運(yùn)輸層,會(huì)更加合適。

可靠傳輸原理的重點(diǎn)總結(jié)一下有:滑動(dòng)窗口、超時(shí)重傳、累積確認(rèn)、選擇確認(rèn)、連續(xù)ARQ 。

停止等待協(xié)議

要實(shí)現(xiàn)可靠傳輸,最簡(jiǎn)便的方法就是:我發(fā)送一個(gè)數(shù)據(jù)包給你,然后你跟我回復(fù)收到,我繼續(xù)發(fā)送下一個(gè)數(shù)據(jù)包。傳輸模型如下:

image

這種“一來(lái)一去”的方法來(lái)保證傳輸可靠就是停止等待協(xié)議(stop-and-wait)。不知道還記不記得前面TCP首部有一個(gè)ack字段,當(dāng)他設(shè)置為1的時(shí)候,表示這個(gè)報(bào)文是一個(gè)確認(rèn)收到報(bào)文。

然后再來(lái)考慮一種情況:丟包。網(wǎng)絡(luò)環(huán)境不可靠,導(dǎo)致每一次發(fā)送的數(shù)據(jù)包可能會(huì)丟失,如果機(jī)器A發(fā)送了數(shù)據(jù)包丟失了,那么機(jī)器B永遠(yuǎn)接收不到數(shù)據(jù),機(jī)器A永遠(yuǎn)在等待。解決這個(gè)問(wèn)題的方法是:超時(shí)重傳 。當(dāng)機(jī)器A發(fā)出一個(gè)數(shù)據(jù)包時(shí)便開始計(jì)時(shí),時(shí)間到還沒收到確認(rèn)回復(fù),就可以認(rèn)為是發(fā)生了丟包,便再次發(fā)送,也就是重傳。

但重傳會(huì)導(dǎo)致另一種問(wèn)題:如果原先的數(shù)據(jù)包并沒有丟失,只是在網(wǎng)絡(luò)中待的時(shí)間比較久,這個(gè)時(shí)候機(jī)器B會(huì)受到兩個(gè)數(shù)據(jù)包,那么機(jī)器B是如何辨別這兩個(gè)數(shù)據(jù)包是屬于同一份數(shù)據(jù)還是不同的數(shù)據(jù)?這就需要前面講過(guò)的方法:給數(shù)據(jù)字節(jié)進(jìn)行編號(hào)。這樣接收方就可以根據(jù)數(shù)據(jù)的字節(jié)編號(hào),得出這些數(shù)據(jù)是接下來(lái)的數(shù)據(jù),還是重傳的數(shù)據(jù)。

在TCP首部有兩個(gè)字段:序號(hào)和確認(rèn)號(hào),他們表示發(fā)送方數(shù)據(jù)第一個(gè)字節(jié)的編號(hào),和接收方期待的下一份數(shù)據(jù)的第一個(gè)字節(jié)的編號(hào)。前面講到TCP是面向字節(jié)流,但是他并不是一個(gè)字節(jié)一個(gè)字節(jié)地發(fā)送,而是一次截取一整段。截取的長(zhǎng)度受多種因素影響,如緩存區(qū)的數(shù)據(jù)大小、數(shù)據(jù)鏈路層限制的幀大小等。

連續(xù)ARQ協(xié)議

停止等待協(xié)議已經(jīng)可以滿足可靠傳輸了,但有一個(gè)致命缺點(diǎn):效率太低。發(fā)送方發(fā)送一個(gè)數(shù)據(jù)包之后便進(jìn)入等待,這個(gè)期間并沒有干任何事,浪費(fèi)了資源。解決的方法是:連續(xù)發(fā)送數(shù)據(jù)包。模型如下:

image

和停止等待最大的不同就是,他會(huì)源源不斷地發(fā)送,接收方源源不斷收到數(shù)據(jù)之后,逐一進(jìn)行確認(rèn)回復(fù)。這樣便極大地提高了效率。但同樣,帶來(lái)了一些額外的問(wèn)題:

發(fā)送是否可以無(wú)限發(fā)送直到把緩沖區(qū)所有數(shù)據(jù)發(fā)送完?不可以。因?yàn)樾枰紤]接收方緩沖區(qū)以及讀取數(shù)據(jù)的能力。如果發(fā)送太快導(dǎo)致接收方無(wú)法接受,那么只是會(huì)頻繁進(jìn)行重傳,浪費(fèi)了網(wǎng)絡(luò)資源。所以發(fā)送方發(fā)送數(shù)據(jù)的范圍,需要考慮到接收方緩沖區(qū)的情況。這就是TCP的流量控制 。解決方法是:滑動(dòng)窗口 。基本模型如下:

image
  • 發(fā)送方需要根據(jù)接收方的緩沖區(qū)大小,設(shè)置自己的可發(fā)送窗口大小,處于窗口內(nèi)的數(shù)據(jù)表示可發(fā)送,之外的數(shù)據(jù)不可發(fā)送。
  • 當(dāng)窗口內(nèi)的數(shù)據(jù)接收到確認(rèn)回復(fù)時(shí),整個(gè)窗口會(huì)往前移動(dòng),直到發(fā)送完成所有的數(shù)據(jù)

在TCP的首部有一個(gè)窗口大小字段,他表示接收方的剩余緩沖區(qū)大小,讓發(fā)送方可以調(diào)整自己的發(fā)送窗口大小。通過(guò)滑動(dòng)窗口,就可以實(shí)現(xiàn)TCP的流量控制,不至于發(fā)送太快,導(dǎo)致太多的數(shù)據(jù)丟失。


連續(xù)ARQ帶來(lái)的第二個(gè)問(wèn)題是:網(wǎng)絡(luò)中充斥著和發(fā)送數(shù)據(jù)包一樣數(shù)據(jù)量的確認(rèn)回復(fù)報(bào)文,因?yàn)槊恳粋€(gè)發(fā)送數(shù)據(jù)包,必須得有一個(gè)確認(rèn)回復(fù)。提高網(wǎng)絡(luò)效率的方法是:累積確認(rèn) 。接收方不需要逐個(gè)進(jìn)行回復(fù),而是累積到一定量的數(shù)據(jù)包之后,告訴發(fā)送方,在此數(shù)據(jù)包之前的數(shù)據(jù)全都收到。例如,收到 1234,接收方只需要告訴發(fā)送方我收到4了,那么發(fā)送方就知道1234都收到了。

第三個(gè)問(wèn)題是:如何處理丟包情況。在停止等待協(xié)議中很簡(jiǎn)單,直接一個(gè)超時(shí)重傳就解決了。但,連續(xù)ARQ中不太一樣。例如:接收方收到了 123 567,六個(gè)字節(jié),編號(hào)為4的字節(jié)丟失了。按照累積確認(rèn)的思路,只能發(fā)送3的確認(rèn)回復(fù),567都必須丟掉,因?yàn)榘l(fā)送方會(huì)進(jìn)行重傳。這就是GBN(go-back-n) 思路。

但是我們會(huì)發(fā)現(xiàn),只需要重傳4即可,這樣不是很浪費(fèi)資源,所以就有了:選擇確認(rèn)SACK 。在TCP報(bào)文的選項(xiàng)字段,可以設(shè)置已經(jīng)收到的報(bào)文段,每一個(gè)報(bào)文段需要兩個(gè)邊界來(lái)進(jìn)行確定。這樣發(fā)送方,就可以根據(jù)這個(gè)選項(xiàng)字段只重傳丟失的數(shù)據(jù)了。

可靠傳輸小結(jié)

到這里關(guān)于TCP的可靠傳輸原理就已經(jīng)介紹的差不多。最后進(jìn)行一個(gè)小結(jié):

  • 通過(guò)連續(xù)ARQ協(xié)議與發(fā)送-確認(rèn)回復(fù)模式來(lái)保證每一個(gè)數(shù)據(jù)包都到達(dá)接收方
  • 通過(guò)給字節(jié)編號(hào)的方法,來(lái)標(biāo)記每一個(gè)數(shù)據(jù)是屬于重傳還是新的數(shù)據(jù)
  • 通過(guò)超時(shí)重傳的方式,來(lái)解決數(shù)據(jù)包在網(wǎng)絡(luò)中丟失的問(wèn)題
  • 通過(guò)滑動(dòng)窗口來(lái)實(shí)現(xiàn)流量控制
  • 通過(guò)累積確認(rèn)+選擇確認(rèn)的方法來(lái)提高確認(rèn)回復(fù)與重傳的效率

當(dāng)然,這只是可靠傳輸?shù)谋揭唤牵信d趣可以再深入去研究(和面試官聊天已經(jīng)差不多了[狗頭])。

擁塞控制

擁塞控制考慮的是另外一個(gè)問(wèn)題:避免網(wǎng)絡(luò)過(guò)分擁擠導(dǎo)致丟包嚴(yán)重,網(wǎng)絡(luò)效率降低 。

拿現(xiàn)實(shí)的交通舉例子:

高速公路同一時(shí)間可通行的汽車數(shù)量是一定的,當(dāng)節(jié)假日時(shí),就會(huì)發(fā)生嚴(yán)重的堵車。在TCP中,數(shù)據(jù)包超時(shí),會(huì)進(jìn)行重傳,也就是會(huì)進(jìn)來(lái)更多的汽車,這時(shí)候更堵,最后導(dǎo)致的結(jié)果就是:丟包-重傳-丟包-重傳。最后整個(gè)網(wǎng)絡(luò)癱瘓了。

這里的擁塞控制和前面的流量控制不是一個(gè)東西,流量控制是擁塞控制的手段:為了避免擁塞,必須對(duì)流量進(jìn)行控制。擁塞控制目的是:限制每個(gè)主機(jī)的發(fā)送的數(shù)據(jù)量,避免網(wǎng)絡(luò)擁塞效率下降。就像廣州等地,限制車牌號(hào)出行是一個(gè)道理。不然大家都堵在路上,誰(shuí)都別想走。

擁塞控制的解決方法是流量控制,流量控制的實(shí)現(xiàn)是滑動(dòng)窗口,所以擁塞控制最終也是通過(guò)限制發(fā)送方的滑動(dòng)窗口大小來(lái)限制流量 。當(dāng)然,擁塞控制的手段不只是流量控制,導(dǎo)致?lián)砣囊蛩赜校郝酚善骶彺?、帶寬、處理器處理速度等等。提升硬件能力(?車道改成8車道)是其中一個(gè)方法,但畢竟硬件提升是有瓶頸的,沒辦法不斷提升,還是需要從tcp本身來(lái)增加算法,解決擁塞。

擁塞控制的重點(diǎn)有4個(gè):慢開始、快恢復(fù)、快重傳、擁塞避免。這里依舊獻(xiàn)祭出大學(xué)老師的ppt圖片:

image

Y軸表示的是發(fā)送方窗口大小,X軸表示的是發(fā)送的輪次(不是字節(jié)編號(hào))。

  • 最開始的時(shí)候,會(huì)把窗口設(shè)置一個(gè)較小的值,然后每輪變?yōu)樵瓉?lái)的兩倍。這是慢開始。
  • 當(dāng)窗口值到達(dá)ssthresh值,這個(gè)值是需要通過(guò)實(shí)時(shí)網(wǎng)絡(luò)情況設(shè)置的一個(gè)窗口限制值,開始進(jìn)入擁塞避免,每輪把窗口值提升1,慢慢試探網(wǎng)絡(luò)的底線。
  • 如果發(fā)生了數(shù)據(jù)超時(shí),表示極可能發(fā)生了擁塞,然后回到慢開始,重復(fù)上面的步驟。
  • 如果收到三個(gè)相同的確認(rèn)回復(fù),表示現(xiàn)在網(wǎng)絡(luò)的情況不太好,把ssthresh的值設(shè)置為原來(lái)的一半,繼續(xù)擁塞避免。這部分稱為快恢復(fù)。
  • 如果收到丟包信息,應(yīng)該盡快把丟失的包重傳一次,這是快重傳。
  • 當(dāng)然,窗口的最終上限是不能無(wú)限上漲的,他不能超過(guò)接收方的緩存區(qū)大小。

通過(guò)這個(gè)算法,就可以在很大程度上,避免網(wǎng)絡(luò)擁擠。

除此之外,還可以讓路由器在緩存即將滿的時(shí)候,告知發(fā)送方我快滿了,而不是等到出現(xiàn)了超時(shí)再進(jìn)行處理,這是主動(dòng)隊(duì)列管理AQM。此外還有很多方法,但是上面的算法是重點(diǎn)。

面向連接

這一小節(jié)講的就是無(wú)人不曉的TCP三次握手與四次揮手這些,經(jīng)過(guò)前面的內(nèi)容,這一小節(jié)其實(shí)已經(jīng)很好理解。

TCP是面向連接的,那連接是什么?這里的連接并不是實(shí)實(shí)在在的連接,而是通信雙方彼此之間的一個(gè)記錄 。TCP是一個(gè)全雙工通信,也就是可以互相發(fā)送數(shù)據(jù),所以雙方都需要記錄對(duì)方的信息。根據(jù)前面的可靠傳輸原理,TCP通信雙方需要為對(duì)方準(zhǔn)備一個(gè)接收緩沖區(qū)可以接收對(duì)方的數(shù)據(jù)、記住對(duì)方的socket知道怎么發(fā)送數(shù)據(jù)、記住對(duì)方的緩沖區(qū)來(lái)調(diào)整自己的窗口大小等等,這些記錄,就是一個(gè)連接。

在運(yùn)輸層小節(jié)中講到,運(yùn)輸層雙方通信的地址是采用socket來(lái)定義的,TCP也不例外。TCP的每一個(gè)連接只能有兩個(gè)對(duì)象,也就是兩個(gè)socket,而不能有三個(gè)。所以socket的定義需要源IP、源端口號(hào)、目標(biāo)IP、目標(biāo)端口號(hào)四個(gè)關(guān)鍵因素,才不會(huì)發(fā)生混亂。

假如TCP和UDP一樣只采用目標(biāo)IP+目標(biāo)端口號(hào)來(lái)定義socket,那么就會(huì)出現(xiàn)多個(gè)發(fā)送方同時(shí)發(fā)送到同一個(gè)目標(biāo)socket的情況。這個(gè)時(shí)候TCP無(wú)法區(qū)分這些數(shù)據(jù)是否來(lái)自不同的發(fā)送方,就會(huì)導(dǎo)致出現(xiàn)錯(cuò)誤。

既然是連接,就有兩個(gè)關(guān)鍵要點(diǎn):建立連接、斷開連接。

建立連接

建立連接的目的就是交換彼此的信息,然后記住對(duì)方的信息。所以雙方都需要發(fā)送彼此的信息給對(duì)方:

image

但前面的可靠傳輸原理告訴我們,數(shù)據(jù)在網(wǎng)絡(luò)中傳輸是不可靠的,需要對(duì)方給予我們一個(gè)確認(rèn)回復(fù),才可以保證消息正確到達(dá)。如下圖:

image

機(jī)器B的確認(rèn)收到和機(jī)器B信息可以進(jìn)行合并,減少次數(shù);而且發(fā)送機(jī)器B給機(jī)器A本身就代表了機(jī)器B已經(jīng)收到了消息,所以最后的示例圖是:

image

步驟如下:

  1. 機(jī)器A發(fā)送syn包向機(jī)器B請(qǐng)求建立TCP連接,并附加上自身的接收緩沖區(qū)信息等,機(jī)器A進(jìn)入SYN_SEND狀態(tài),表示請(qǐng)求已經(jīng)發(fā)送正在等待回復(fù);
  2. 機(jī)器B收到請(qǐng)求之后,根據(jù)機(jī)器A的信息記錄下來(lái),并創(chuàng)建自身的接收緩存區(qū),向機(jī)器A發(fā)送syn+ack的合成包,同時(shí)自身進(jìn)入SYN_RECV狀態(tài),表示已經(jīng)準(zhǔn)備好了,等待機(jī)器A 的回復(fù)就可以向A發(fā)送數(shù)據(jù);
  3. 機(jī)器A收到回復(fù)之后記錄機(jī)器B 的信息,發(fā)送ack信息,自身進(jìn)入ESTABLISHED狀態(tài),表示已經(jīng)完全準(zhǔn)備好了,可以進(jìn)行發(fā)送和接收;
  4. 機(jī)器B收到ACK數(shù)據(jù)之后,進(jìn)入ESTABLISHED狀態(tài)。

三次消息的發(fā)送,稱為三次握手。

斷開連接

斷開連接和三次握手類似,直接上圖:

image
  1. 機(jī)器A發(fā)送完數(shù)據(jù)之后,向機(jī)器B請(qǐng)求斷開連接,自身進(jìn)入FIN_WAIT_1狀態(tài),表示數(shù)據(jù)發(fā)送完成且已經(jīng)發(fā)送FIN包(FIN標(biāo)志位為1);

  2. 機(jī)器B收到FIN包之后,回復(fù)ack包表示已經(jīng)收到,但此時(shí)機(jī)器B可能還有數(shù)據(jù)沒發(fā)送完成,自身進(jìn)入CLOSE_WAIT狀態(tài),表示對(duì)方已發(fā)送完成且請(qǐng)求關(guān)閉連接,自身發(fā)送完成之后可以關(guān)閉連接;

  3. 機(jī)器B數(shù)據(jù)發(fā)送完成之后,發(fā)送FIN包給機(jī)器B ,自身進(jìn)入LAST_ACK狀態(tài),表示等待一個(gè)ACK包即可關(guān)閉連接;

  4. 機(jī)器A收到FIN包之后,知道機(jī)器B也發(fā)送完成了,回復(fù)一個(gè)ACK包,并進(jìn)入TIME_WAIT狀態(tài)

    TIME_WAIT狀態(tài)比較特殊。當(dāng)機(jī)器A收到機(jī)器B的FIN包時(shí),理想狀態(tài)下,確實(shí)是可以直接關(guān)閉連接了;但是:

    1. 我們知道網(wǎng)絡(luò)是不穩(wěn)定的,可能機(jī)器B 發(fā)送了一些數(shù)據(jù)還沒到達(dá)(比FIN包慢);
    2. 同時(shí)回復(fù)的ACK包可能丟失了,機(jī)器B會(huì)重傳FIN包;

    如果此時(shí)機(jī)器A馬上關(guān)閉連接,會(huì)導(dǎo)致數(shù)據(jù)不完整、機(jī)器B無(wú)法釋放連接等問(wèn)題。所以此時(shí)機(jī)器A需要等待2個(gè)報(bào)文生存最大時(shí)長(zhǎng),確保網(wǎng)絡(luò)中沒有任何遺留報(bào)文了,再關(guān)閉連接

  5. 最后,機(jī)器A等待兩個(gè)報(bào)文存活最大時(shí)長(zhǎng)之后,機(jī)器B 接收到ACK報(bào)文之后,均關(guān)閉連接,進(jìn)入CLASED狀態(tài)

雙方之間4次互相發(fā)送報(bào)文來(lái)斷開連接的過(guò)程,就是四次揮手

現(xiàn)在,對(duì)于為什么握手是三次揮手是四次、一定要三次/四次嗎、為什么要停留2msl再關(guān)閉連接等等這些問(wèn)題,就都解決了。

UDP協(xié)議

運(yùn)輸層協(xié)議除了TCP,還有大名鼎鼎的UDP。如果說(shuō)TCP憑借他完善穩(wěn)定的功能獨(dú)樹一幟,那UDP就是精簡(jiǎn)主義亂拳打死老師傅。

UDP只實(shí)現(xiàn)了運(yùn)輸層最少的功能:進(jìn)程間通信。對(duì)于應(yīng)用層傳下來(lái)的數(shù)據(jù),UDP只是附加一個(gè)首部就直接交給網(wǎng)絡(luò)層了。UDP的頭部非常簡(jiǎn)單,只有三部分:

  • 源端口、目標(biāo)端口:端口號(hào)用來(lái)區(qū)分主機(jī)的不同進(jìn)程
  • 校驗(yàn)碼:用于校驗(yàn)數(shù)據(jù)包在傳輸?shù)倪^(guò)程中沒有出現(xiàn)錯(cuò)誤,例如某個(gè)1變成了0
  • 長(zhǎng)度:報(bào)文的長(zhǎng)度

所以UDP的功能也只有兩個(gè):校驗(yàn)數(shù)據(jù)報(bào)是否發(fā)生錯(cuò)誤、區(qū)分不同的進(jìn)程通信。

但,TCP的功能雖然多,但同時(shí)也是要付出相對(duì)應(yīng)的代價(jià)。例如面向連接的特性,在建立和斷開連接的時(shí)候會(huì)有開銷;擁塞控制的特性,會(huì)限制傳輸?shù)纳舷薜鹊取O旅鎭?lái)羅列一下UDP的優(yōu)缺點(diǎn):

UDP的缺點(diǎn)

  • 無(wú)法保證消息完整、正確到達(dá),UDP是一個(gè)不可靠的傳輸協(xié)議;
  • 缺少擁塞控制容易互相競(jìng)爭(zhēng)資源導(dǎo)致網(wǎng)絡(luò)系統(tǒng)癱瘓

UDP的優(yōu)點(diǎn)

  • 效率更快;不需要建立連接以及擁塞控制
  • 連接更多的客戶;沒有連接狀態(tài),不需要為每個(gè)客戶創(chuàng)建緩存等
  • 分組首部字節(jié)少,開銷??;TCP首部固定首部是20字節(jié),而UDP只有8字節(jié);更小的首部意味著更大比例的數(shù)據(jù)部分
  • 在一些需要高效率允許可限度誤差的場(chǎng)景下可以使用。如直播場(chǎng)景,并不需要保證每個(gè)數(shù)據(jù)包都完整到達(dá),允許一定的丟包率,這個(gè)時(shí)候TCP的可靠特性反而成為了累贅;精簡(jiǎn)的UDP更高的效率是更加適合的選擇
  • 可以進(jìn)行廣播;UDP并不是面向連接的,所以可以同時(shí)對(duì)多個(gè)進(jìn)程進(jìn)行發(fā)送報(bào)文

UDP適用場(chǎng)景

UDP適用于對(duì)傳輸模型需要應(yīng)用層高度自定義、允許出現(xiàn)丟包、需要高效率的場(chǎng)景、需要廣播;例如

  • 視屏直播
  • DNS
  • RIP路由選擇協(xié)議

其他補(bǔ)充

分塊傳輸

我們可以發(fā)現(xiàn),運(yùn)輸層在傳輸數(shù)據(jù)的時(shí)候,并不是把整個(gè)數(shù)據(jù)包加個(gè)首部直接發(fā)送過(guò)去,而是會(huì)拆分成多個(gè)報(bào)文分開發(fā)送;那他這樣做原因是什么?

有讀者可能會(huì)想到:數(shù)據(jù)鏈路層限制了數(shù)據(jù)長(zhǎng)度只能有1460。那數(shù)據(jù)鏈路層為什么要這么限制?他的本質(zhì)原因就是:網(wǎng)絡(luò)是不穩(wěn)定的。如果報(bào)文太長(zhǎng),那么極有可能在傳輸一般的時(shí)候突然中斷了,這個(gè)時(shí)候就要整個(gè)數(shù)據(jù)重傳,效率就降低了。把數(shù)據(jù)拆分成多個(gè)數(shù)據(jù)報(bào),那么當(dāng)某個(gè)數(shù)據(jù)報(bào)丟失,只需要重傳該數(shù)據(jù)報(bào)即可。

那是不是拆分得越細(xì)越好?報(bào)文中數(shù)據(jù)字段長(zhǎng)度太低,會(huì)使得首部的占比太大,這樣首部就會(huì)成為網(wǎng)絡(luò)傳輸最大的負(fù)擔(dān)了。例如1000字節(jié),每個(gè)報(bào)文首部是40字節(jié),如果拆分成10個(gè)報(bào)文,那么只需要傳輸400字節(jié)的首部;而如果拆分成1000個(gè),那么需要傳輸40000字節(jié)的首部,效率就極大地降低了。

路由轉(zhuǎn)換

先看下圖:

image
  • 正常情況下,主機(jī)A的數(shù)據(jù)包可以又 1-3-6-7路徑進(jìn)行傳送
  • 如果路由3壞掉了,那么可以從 1-4-6-7進(jìn)行傳送
  • 如果4也壞掉了,那么只能從2-5-6-7傳送
  • 如果5壞掉了,那么就中斷線路了

可以看出來(lái),使用路由轉(zhuǎn)發(fā)的好處是:提高網(wǎng)絡(luò)的容錯(cuò)率,本質(zhì)原因依舊是網(wǎng)絡(luò)是不穩(wěn)定的 。即使壞掉幾個(gè)路由器,網(wǎng)絡(luò)依舊暢通。但是如果壞掉路由器6那就直接導(dǎo)致主機(jī)A和主機(jī)B無(wú)法通信,所以要避免這種核心路由器的存在。

使用路由的好處還有:分流。如果一條線路太擁堵,可以從別的路線進(jìn)行傳輸,提高效率。

粘包與拆包

在面向字節(jié)流那一小節(jié)講過(guò),TCP不懂這些數(shù)據(jù)流的意義,他只知道從應(yīng)用層拿到數(shù)據(jù)流,切割成一份份報(bào)文,然后發(fā)送給目標(biāo)對(duì)象。而如果應(yīng)用層傳輸下來(lái)的是兩個(gè)數(shù)據(jù)包,那么極有可能出現(xiàn)這種情況:

image
  • 應(yīng)用層需要向目標(biāo)進(jìn)程發(fā)送兩份數(shù)據(jù),一份音頻,一份文本
  • TCP只知道接收到一個(gè)流,并把流拆分成4段進(jìn)行發(fā)送
  • 中間第二個(gè)報(bào)文的數(shù)據(jù)就出現(xiàn)兩個(gè)文件的數(shù)據(jù)混在一起,這就是粘包
  • 目標(biāo)進(jìn)程應(yīng)用層在接收到數(shù)據(jù)之后,需要把這些數(shù)據(jù)拆分成正確的兩個(gè)文件,就是拆包

粘包與拆包都是應(yīng)用層需要解決的問(wèn)題,可以在每個(gè)文件的最后附加上一些特殊的字節(jié),如換行符;或者控制每個(gè)報(bào)文只包含一個(gè)文件的數(shù)據(jù),不足的用0補(bǔ)充等等。

惡意攻擊

TCP的面向連接特點(diǎn)可能會(huì)被惡意的人利用,對(duì)服務(wù)器進(jìn)行攻擊。

前面我們知道,當(dāng)我們向一個(gè)主機(jī)發(fā)送syn包請(qǐng)求創(chuàng)建連接時(shí),服務(wù)器會(huì)為我們創(chuàng)建緩沖區(qū)等,然后向我們返回syn+ack報(bào)文;如果我們偽造IP和端口,向一個(gè)服務(wù)器進(jìn)行海量的請(qǐng)求,會(huì)使得服務(wù)器創(chuàng)建了大量的創(chuàng)建一半的TCP連接,使得其無(wú)法正常響應(yīng)用戶的請(qǐng)求,導(dǎo)致服務(wù)器癱瘓。

解決的方法可以有限制IP的創(chuàng)建連接數(shù)、讓創(chuàng)建一半的tcp連接在更短的時(shí)間內(nèi)自行關(guān)閉、延緩接收緩沖區(qū)內(nèi)存的分配等等。

長(zhǎng)連接

我們向服務(wù)器的每一次請(qǐng)求都需要?jiǎng)?chuàng)建一個(gè)TCP連接,服務(wù)器返回?cái)?shù)據(jù)之后就會(huì)關(guān)閉連接;如果在短時(shí)間內(nèi)有大量的請(qǐng)求,那么頻繁創(chuàng)建TCP連接關(guān)閉TCP連接是一個(gè)很浪費(fèi)資源的行為。所以我們可以讓TCP連接不要關(guān)閉,在這個(gè)期間進(jìn)行請(qǐng)求,提高效率。

需要注意長(zhǎng)連接維持時(shí)間、創(chuàng)建條件等,避免被惡意利用創(chuàng)建大量的長(zhǎng)連接,消耗殆盡服務(wù)器的資源。

最后

以前學(xué)習(xí)的時(shí)候覺得這些東西好像沒什么卵用,貌似就是用來(lái)考試的。事實(shí)上,在沒應(yīng)用到的時(shí)候,對(duì)這些知識(shí)很難有更深層次的認(rèn)知,例如現(xiàn)在我看上面的總結(jié),很多只是表面上的認(rèn)知,不知道他背后代表的真正含義。

但當(dāng)我學(xué)習(xí)的更加廣泛、深入,會(huì)對(duì)這些知識(shí)有越來(lái)越深刻的認(rèn)識(shí)。有那么幾個(gè)瞬間覺得:哦原來(lái)那個(gè)東西是這樣運(yùn)用,那個(gè)東西是這樣的啊,原來(lái)學(xué)了是真的有用。

現(xiàn)在可能學(xué)了之后沒有什么感覺,但是當(dāng)用到或者學(xué)到相關(guān)的應(yīng)用時(shí),會(huì)有一個(gè)頓悟感,會(huì)瞬間收獲很多。

覺得有幫助留個(gè)贊鼓勵(lì)一下作者吧~

全文到此,原創(chuàng)不易,覺得有幫助可以點(diǎn)贊收藏評(píng)論轉(zhuǎn)發(fā)。
筆者才疏學(xué)淺,文章有錯(cuò)誤或有不同觀點(diǎn)歡迎評(píng)論區(qū)交流。
如需轉(zhuǎn)載請(qǐng)?jiān)u論區(qū)或私信告知即可。

另外歡迎光臨筆者的個(gè)人博客:傳送門

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容