TCP頭格式有哪些
- 源端口號(hào)和目標(biāo)端口號(hào):16位字段,用于標(biāo)識(shí)TCP連接的源和目標(biāo)端口號(hào)。
- 序列號(hào)(Sequence Number):32位字段,用于標(biāo)識(shí)發(fā)送的數(shù)據(jù)字節(jié)流中的第一個(gè)字節(jié)的序號(hào)。
- 確認(rèn)號(hào)(Acknowledgment Number):32位字段,確認(rèn)收到的字節(jié)序號(hào),即期望接收的下一個(gè)字節(jié)的序號(hào)。
- 數(shù)據(jù)偏移:4位字段,指示TCP頭部的長(zhǎng)度,以32位字為單位。
- 保留、U、A、P、R、S、F:這些標(biāo)志位用于控制TCP連接的狀態(tài)和行為,例如URG(緊急指針有效)、ACK(確認(rèn)號(hào)有效)、PSH(接收方應(yīng)盡快將數(shù)據(jù)交給應(yīng)用)、RST(重置連接)、SYN(建立連接請(qǐng)求)、FIN(關(guān)閉連接)。
- 窗口大?。╓indow Size):16位字段,表示接收方的接收窗口大小,用于流量控制。
- 校驗(yàn)和(Checksum):16位字段,用于檢測(cè)TCP頭部和數(shù)據(jù)是否在傳輸過(guò)程中發(fā)生錯(cuò)誤。
- 緊急指針(Urgent Pointer):16位字段,僅在URG標(biāo)志位設(shè)置為1時(shí)有效,用于指示緊急數(shù)據(jù)的字節(jié)偏移。
- 選項(xiàng)(可選):用于在TCP頭部中指定一些附加選項(xiàng),如最大報(bào)文段長(zhǎng)度(MSS)等。
- 填充(Padding):用于確保TCP頭部達(dá)到指定長(zhǎng)度的填充字段
為什么需要TCP,TCP工作在哪
IP層不可靠,不保證網(wǎng)絡(luò)包的交付,不保證網(wǎng)絡(luò)包的按序交付,也不保證網(wǎng)絡(luò)包中的數(shù)據(jù)的完整性。因?yàn)?TCP 是一個(gè)工作在傳輸層的可靠數(shù)據(jù)傳輸?shù)姆?wù),它能確保接收端接收的網(wǎng)絡(luò)包是無(wú)損壞、無(wú)間隔、非冗余和按序的。
什么是TCP
TCP 是面向連接的、可靠的、基于字節(jié)流的傳輸層通信協(xié)議。
- 面向連接:再進(jìn)行數(shù)據(jù)傳輸之前,通信的兩端需要建立一個(gè)可靠的連接,通過(guò)三次握手來(lái)建立
- 可靠的:TCP 可以保證一個(gè)報(bào)文一定能夠到達(dá)接收端,通過(guò)序列號(hào)、確認(rèn)應(yīng)答和重傳等機(jī)制來(lái)確保數(shù)據(jù)的可靠傳輸
- 字節(jié)流:指的是在TCP連接中,數(shù)據(jù)被視為連續(xù)的字節(jié)流而不是分割成固定大小的數(shù)據(jù)塊或消息。當(dāng)應(yīng)用程序發(fā)送數(shù)據(jù)時(shí),TCP會(huì)將這些數(shù)據(jù)拆分成較小的數(shù)據(jù)塊,并為每個(gè)數(shù)據(jù)塊添加TCP頭部信息,然后將它們作為字節(jié)流發(fā)送
什么是TCP連接
建立一個(gè)TCP連接是需要客戶端與服務(wù)端達(dá)成上述三個(gè)信息共識(shí)
- Socket:用IP地址和端口號(hào)組成
- 序列號(hào):用來(lái)解決亂序問(wèn)題
- 窗口大?。河脕?lái)做流量控制
TCP連接(Transmission Control Protocol connection)是計(jì)算機(jī)網(wǎng)絡(luò)中的一種通信方式,它建立在傳輸控制協(xié)議(TCP)之上。TCP連接是一種面向連接的通信方式,意味著在數(shù)據(jù)傳輸之前,通信的兩端(通常是客戶端和服務(wù)器)需要通過(guò)一系列握手來(lái)建立一個(gè)可靠的連接。
如何確定一個(gè)TCP連接
源地址、源端口、目的地址、目的端口(地址32位在IP頭部,端口16位在TCP頭部)
TCP最大連接數(shù)=客戶端IP數(shù)*客戶端端口數(shù)
TCP和UDP的區(qū)別,以及場(chǎng)景
TCP(傳輸控制協(xié)議)和UDP(用戶數(shù)據(jù)報(bào)協(xié)議)是兩種常見(jiàn)的傳輸層協(xié)議,它們?cè)诰W(wǎng)絡(luò)通信中有著不同的特點(diǎn)和應(yīng)用場(chǎng)景。
TCP的特點(diǎn)和應(yīng)用場(chǎng)景:
- 面向連接:TCP使用三次握手建立連接,確保通信雙方建立可靠的連接后再進(jìn)行數(shù)據(jù)傳輸。
- 可靠性:TCP保證數(shù)據(jù)的可靠傳輸,通過(guò)序列號(hào)、確認(rèn)應(yīng)答和重傳機(jī)制來(lái)確保數(shù)據(jù)的完整性和正確性。
- 有序性:TCP會(huì)按照發(fā)送順序保證數(shù)據(jù)包在接收端按序重組,避免數(shù)據(jù)包亂序的情況。
- 流控制和擁塞控制:TCP通過(guò)流控制和擁塞控制算法來(lái)平衡發(fā)送和接收數(shù)據(jù)的速率,防止網(wǎng)絡(luò)擁塞。
- 應(yīng)用場(chǎng)景:TCP適用于對(duì)數(shù)據(jù)完整性和可靠性要求較高的應(yīng)用,如網(wǎng)頁(yè)瀏覽、文件傳輸、電子郵件等。
UDP的特點(diǎn)和應(yīng)用場(chǎng)景:
- 無(wú)連接:UDP不需要建立連接,直接將數(shù)據(jù)包發(fā)送出去,適用于無(wú)需建立持久連接的通信場(chǎng)景。
- 不可靠性:UDP不保證數(shù)據(jù)的可靠傳輸,數(shù)據(jù)包可能丟失、重復(fù)、亂序,需要應(yīng)用層自行處理丟失情況。
- 無(wú)序性:UDP的數(shù)據(jù)包可能按照發(fā)送順序的不同在接收端亂序到達(dá),應(yīng)用層需要處理亂序的情況。
- 低延遲:由于不需要建立連接和擁有較少的控制機(jī)制,UDP傳輸具有較低的延遲。
- 應(yīng)用場(chǎng)景:UDP適用于對(duì)實(shí)時(shí)性要求較高的應(yīng)用,如視頻直播、在線游戲、音頻通話等。在這些場(chǎng)景下,實(shí)時(shí)性更重要,而對(duì)于數(shù)據(jù)丟失的情況,可以通過(guò)應(yīng)用層的處理來(lái)進(jìn)行容忍或糾正。
分片不同
- TCP 的數(shù)據(jù)大小如果大于 MSS(最大分段大小) 大小,則會(huì)在傳輸層進(jìn)行分片,目標(biāo)主機(jī)收到后,也同樣在傳輸層組裝 TCP 數(shù)據(jù)包,如果中途丟失了一個(gè)分片,只需要傳輸丟失的這個(gè)分片。MSS:它是TCP協(xié)議中的一個(gè)參數(shù),用于指示在TCP連接中每個(gè)數(shù)據(jù)包的最大有效載荷大?。闯CP頭部后的數(shù)據(jù)部分大?。?。
- UDP 的數(shù)據(jù)大小如果大于 MTU(最大傳輸單元) 大小,則會(huì)在 IP 層進(jìn)行分片,目標(biāo)主機(jī)收到后,在 IP 層組裝完數(shù)據(jù),接著再傳給傳輸層。MTU :它是指在網(wǎng)絡(luò)通信中能夠承載的最大數(shù)據(jù)包的大小。MTU是以字節(jié)為單位來(lái)衡量的。
綜上所述,TCP和UDP各有優(yōu)勢(shì),應(yīng)根據(jù)具體應(yīng)用場(chǎng)景的需求來(lái)選擇合適的協(xié)議。對(duì)于重要數(shù)據(jù)的傳輸和確保數(shù)據(jù)可靠性的應(yīng)用,可以選擇TCP。而對(duì)于實(shí)時(shí)性要求較高的應(yīng)用,可以選擇UDP。
TCP和UDP能共用一個(gè)端口?
答案:可以
**簡(jiǎn)介回答:**端口號(hào)的目的主要是為了區(qū)分同一個(gè)主機(jī)不同應(yīng)用程序的數(shù)據(jù)包,傳輸層有兩個(gè)傳輸協(xié)議分別是 TCP 和 UDP,在內(nèi)核中是兩個(gè)完全獨(dú)立的軟件模塊,當(dāng)主機(jī)收到數(shù)據(jù)包后,可以在 IP 包頭的「協(xié)議號(hào)」字段知道該數(shù)據(jù)包是 TCP/UDP,所以可以根據(jù)這個(gè)信息確定送給哪個(gè)模塊(TCP/UDP)處理,送給 TCP/UDP 模塊的報(bào)文根據(jù)「端口號(hào)」確定送給哪個(gè)應(yīng)用程序處理。
**詳細(xì)回答:**在一般情況下,TCP和UDP是不能共用一個(gè)端口的。TCP和UDP是兩種不同的傳輸層協(xié)議,它們使用不同的端口來(lái)進(jìn)行通信。每個(gè)網(wǎng)絡(luò)通信應(yīng)用都使用特定的端口號(hào)來(lái)與其他應(yīng)用進(jìn)行交流。TCP和UDP各自有獨(dú)立的端口號(hào)空間,這意味著一個(gè)特定的端口號(hào)在TCP和UDP之間可以同時(shí)存在,但它們對(duì)應(yīng)的是不同的應(yīng)用或服務(wù)。例如,HTTP通常使用TCP協(xié)議在80端口進(jìn)行通信,DNS通常使用UDP協(xié)議在53端口進(jìn)行通信。這意味著在同一時(shí)間,80端口可能被TCP協(xié)議的HTTP使用,而53端口可能被UDP協(xié)議的DNS使用,二者不會(huì)相互干擾。然而,也有一些特殊情況下,某些應(yīng)用或協(xié)議可以同時(shí)使用TCP和UDP共享同一個(gè)端口。這被稱為"TCP/UDP多路復(fù)用"或"TCP/UDP Port Sharing"。這種情況下,應(yīng)用程序需要負(fù)責(zé)處理接收到的數(shù)據(jù),并根據(jù)數(shù)據(jù)包的內(nèi)容區(qū)分使用TCP還是UDP來(lái)處理數(shù)據(jù)。這樣的機(jī)制通常由應(yīng)用層協(xié)議自行實(shí)現(xiàn),而不是由TCP和UDP協(xié)議棧提供的默認(rèn)功能??偟膩?lái)說(shuō),大多數(shù)情況下,TCP和UDP使用獨(dú)立的端口來(lái)避免混淆和沖突。但特定的應(yīng)用場(chǎng)景下,TCP/UDP多路復(fù)用可以實(shí)現(xiàn)在同一個(gè)端口上同時(shí)使用TCP和UDP。
TCP的建立
TCP三次握手過(guò)程
TCP三次握手是建立TCP連接的過(guò)程,它用于確保客戶端和服務(wù)器之間建立可靠的連接。以下是TCP三次握手的過(guò)程:
-
第一次握手(SYN):
- 客戶端向服務(wù)器發(fā)送一個(gè)連接請(qǐng)求報(bào)文段,其中設(shè)置了SYN標(biāo)志位(SYN=1)。
- 客戶端選擇一個(gè)初始序列號(hào)(ISN,Initial Sequence Number),用于后續(xù)數(shù)據(jù)的傳輸。
-
第二次握手(SYN+ACK):
- 服務(wù)器收到客戶端的連接請(qǐng)求后,回復(fù)一個(gè)確認(rèn)報(bào)文段作為回應(yīng)。
- 服務(wù)器在回復(fù)的報(bào)文段中設(shè)置了SYN和ACK標(biāo)志位(SYN=1,ACK=1)。
- 服務(wù)器也選擇一個(gè)初始序列號(hào)(ISN)用于后續(xù)數(shù)據(jù)傳輸,并將確認(rèn)號(hào)(ACK)設(shè)置為客戶端的初始序列號(hào)(ISN + 1)。
-
第三次握手(ACK):
- 客戶端收到服務(wù)器的確認(rèn)報(bào)文段后,向服務(wù)器發(fā)送一個(gè)確認(rèn)報(bào)文段。
- 客戶端在這個(gè)報(bào)文段中設(shè)置了ACK標(biāo)志位(ACK=1)。
- 客戶端的確認(rèn)號(hào)(ACK)被設(shè)置為服務(wù)器的初始序列號(hào)(ISN + 1),表示已收到服務(wù)器的回應(yīng)。
一旦服務(wù)器收到客戶端的確認(rèn)報(bào)文段,TCP連接就建立成功,可以開(kāi)始進(jìn)行數(shù)據(jù)傳輸。在這個(gè)過(guò)程中,客戶端和服務(wù)器通過(guò)交換序列號(hào)和確認(rèn)號(hào)來(lái)確保彼此能夠正確接收數(shù)據(jù),從而建立可靠的連接。第三次握手是可以攜帶數(shù)據(jù)的,前兩次握手是不可以攜帶數(shù)據(jù)的
為什么是三次握手、不是兩次、四次
- 三次握手才可以阻止重復(fù)歷史連接的初始化(主要原因)
- 三次握手才可以同步雙方的初始序列號(hào)
- 三次握手才可以避免資源浪費(fèi)
- 「兩次握手」:無(wú)法防止歷史連接的建立,會(huì)造成雙方資源的浪費(fèi),也無(wú)法可靠的同步雙方序列號(hào);
- 「四次握手」:三次握手就已經(jīng)理論上最少可靠連接建立,所以不需要使用更多的通信次數(shù)。
why每次建立連接,初始化序列號(hào)要求不一樣
- 為了防止歷史報(bào)文被下一個(gè)相同四元組的連接接收(主要方面);
- 為了安全性,防止黑客偽造的相同序列號(hào)的 TCP 報(bào)文被對(duì)方接收;
增強(qiáng)安全性: 選擇不同的初始序列號(hào)可以增強(qiáng)安全性。如果每次建立連接時(shí)初始序列號(hào)都是相同的,那么攻擊者可以利用這個(gè)預(yù)測(cè)性來(lái)發(fā)動(dòng)網(wǎng)絡(luò)攻擊,例如TCP序列號(hào)預(yù)測(cè)攻擊。通過(guò)選擇不同的初始序列號(hào),可以增加攻擊者猜測(cè)序列號(hào)的難度,提高連接的安全性。
防止舊連接的混淆: TCP協(xié)議要求,當(dāng)處于TIME_WAIT狀態(tài)的連接結(jié)束后,必須經(jīng)過(guò)一段時(shí)間的等待才能確保網(wǎng)絡(luò)上的所有數(shù)據(jù)包都被丟棄。在此期間,如果有新的連接建立并選擇了與已結(jié)束的舊連接相同的初始序列號(hào),可能會(huì)導(dǎo)致新連接收到舊連接的數(shù)據(jù)包,從而造成混淆。通過(guò)選擇不同的初始序列號(hào),可以避免這種情況的發(fā)生。
初始化序列號(hào)ISN是如何隨機(jī)產(chǎn)生的
起始 ISN
是基于時(shí)鐘的,每 4 微秒 + 1,轉(zhuǎn)一圈要 4.55 個(gè)小時(shí),RFC793 提到初始化序列號(hào) ISN 隨機(jī)生成算法:ISN = M + F(localhost, localport, remotehost, remoteport)。
-
M
是一個(gè)計(jì)時(shí)器,這個(gè)計(jì)時(shí)器每隔 4 微秒加 1。 -
F
是一個(gè) Hash 算法,根據(jù)源 IP、目的 IP、源端口、目的端口生成一個(gè)隨機(jī)數(shù)值。要保證 Hash 算法不能被外部輕易推算得出,用 MD5 算法是一個(gè)比較好的選擇。
IP層會(huì)分片,whyTCP層還需要MSS
- 如果一個(gè)IP分片丟失,整個(gè)IP報(bào)文的所有分片都得重傳,因?yàn)镮P層本身沒(méi)有超時(shí)重傳機(jī)制,由傳輸層TCP來(lái)負(fù)責(zé)超時(shí)和重傳,
當(dāng)一個(gè)TCP分片丟失,重發(fā)時(shí)以MSS
- TCP層發(fā)現(xiàn)數(shù)據(jù)超過(guò)MSS時(shí),會(huì)先進(jìn)行分片,然后由它形成的IP包的長(zhǎng)度也就不會(huì)大于MTU
雖然IP層可以對(duì)大于MTU的數(shù)據(jù)包進(jìn)行分片,但TCP層的MSS(最大分段大小)參數(shù)仍然非常重要,因?yàn)門(mén)CP層的MSS決定了在TCP連接中每個(gè)數(shù)據(jù)包的最大有效載荷大小,而這對(duì)于TCP連接的性能和效率至關(guān)重要。下面解釋為什么TCP層需要MSS:
1. 避免不必要的分片: TCP層的MSS參數(shù)允許TCP在發(fā)送數(shù)據(jù)之前,根據(jù)網(wǎng)絡(luò)的MTU,選擇一個(gè)適當(dāng)?shù)淖畲笥行лd荷大小。如果TCP層的數(shù)據(jù)包大小超過(guò)了MTU,IP層會(huì)對(duì)數(shù)據(jù)包進(jìn)行分片。分片增加了網(wǎng)絡(luò)傳輸?shù)膹?fù)雜性,也可能導(dǎo)致丟失或亂序的問(wèn)題。通過(guò)設(shè)置適當(dāng)?shù)腗SS,TCP可以盡量避免數(shù)據(jù)包被分片,提高數(shù)據(jù)傳輸?shù)男屎涂煽啃浴?/p>
2. 控制擁塞窗口: TCP使用擁塞控制算法來(lái)避免網(wǎng)絡(luò)擁塞。MSS是擁塞窗口的一個(gè)重要參數(shù)。擁塞窗口決定了TCP可以發(fā)送的未確認(rèn)數(shù)據(jù)量,通過(guò)調(diào)整MSS,可以控制擁塞窗口的大小,從而適應(yīng)網(wǎng)絡(luò)的擁塞狀況,防止過(guò)多的數(shù)據(jù)注入導(dǎo)致網(wǎng)絡(luò)擁塞。
3. 保持連接的可靠性: TCP層的MSS也與TCP連接的可靠性密切相關(guān)。較大的MSS可以減少連接的握手次數(shù)和數(shù)據(jù)包數(shù)量,從而降低連接建立和維護(hù)的開(kāi)銷(xiāo),提高連接的可靠性。
總的來(lái)說(shuō),雖然IP層可以進(jìn)行分片,但TCP層的MSS仍然非常重要,它可以避免不必要的分片,控制擁塞窗口,提高連接的可靠性,從而優(yōu)化TCP連接的性能和效率。通過(guò)合理設(shè)置MSS,TCP可以更好地適應(yīng)不同網(wǎng)絡(luò)環(huán)境,實(shí)現(xiàn)高效、可靠的數(shù)據(jù)傳輸。
第一次握手丟失會(huì)發(fā)生什么
客戶端就會(huì)觸發(fā)「超時(shí)重傳」機(jī)制,重傳 SYN 報(bào)文,而且重傳的 SYN 報(bào)文的序列號(hào)都是一樣的。不同操作系統(tǒng)超時(shí)時(shí)間不同,有的1秒,有的3秒,Linux里客戶端SYN報(bào)文最大重傳次數(shù)由(tcp_syn_retries)參數(shù)控制,默認(rèn)值:5。每次超時(shí)的時(shí)間是上一次的 2 倍
第二次握手丟失了,會(huì)發(fā)生什么
客戶端就會(huì)觸發(fā)超時(shí)重傳機(jī)制,重傳 SYN 報(bào)文。服務(wù)端這邊會(huì)觸發(fā)超時(shí)重傳機(jī)制,重傳 SYN-ACK 報(bào)文。在 Linux 下,SYN-ACK 報(bào)文的最大重傳次數(shù)由 tcp_synack_retries
內(nèi)核參數(shù)決定,默認(rèn)值是 5。
第三次握手丟失了,會(huì)發(fā)生什么
服務(wù)端就會(huì)觸發(fā)超時(shí)重傳機(jī)制,重傳 SYN-ACK 報(bào)文,直到收到第三次握手,或者達(dá)到最大重傳次數(shù)。ACK 報(bào)文是不會(huì)有重傳的,當(dāng) ACK 丟失了,就由對(duì)方重傳對(duì)應(yīng)的報(bào)文。
SYN攻擊,如何避免
半連接隊(duì)列和全連接隊(duì)列
正常流程:
- 當(dāng)服務(wù)端接收到客戶端的 SYN 報(bào)文時(shí),會(huì)創(chuàng)建一個(gè)半連接的對(duì)象,然后將其加入到內(nèi)核的「 SYN 隊(duì)列」;
- 接著發(fā)送 SYN + ACK 給客戶端,等待客戶端回應(yīng) ACK 報(bào)文;
- 服務(wù)端接收到 ACK 報(bào)文后,從「 SYN 隊(duì)列」取出一個(gè)半連接對(duì)象,然后創(chuàng)建一個(gè)新的連接對(duì)象放入到「 Accept 隊(duì)列」;
- 應(yīng)用通過(guò)調(diào)用
accpet()
socket 接口,從「 Accept 隊(duì)列」取出連接對(duì)象。
不管是半連接隊(duì)列還是全連接隊(duì)列,都有最大長(zhǎng)度限制,超過(guò)限制時(shí),默認(rèn)情況都會(huì)丟棄報(bào)文。
SYN 攻擊方式最直接的表現(xiàn)就會(huì)把 TCP 半連接隊(duì)列打滿,這樣當(dāng) TCP 半連接隊(duì)列滿了,后續(xù)再在收到 SYN 報(bào)文就會(huì)丟棄,導(dǎo)致客戶端無(wú)法和服務(wù)端建立連接。
避免 SYN 攻擊方式
可以有以下四種方法:
- 調(diào)大 netdev_max_backlog;當(dāng)網(wǎng)卡接收數(shù)據(jù)包的速度大于內(nèi)核處理的速度時(shí),會(huì)有一個(gè)隊(duì)列保存這些數(shù)據(jù)包,隊(duì)列長(zhǎng)度默認(rèn)值1000
- 增大 TCP 半連接隊(duì)列;
- 開(kāi)啟 tcp_syncookies;
- 減少 SYN+ACK 重傳次數(shù)
TCP連接斷開(kāi)
四次揮手過(guò)程
TCP四次揮手是終止TCP連接的過(guò)程,用于斷開(kāi)客戶端和服務(wù)器之間的連接。以下是TCP四次揮手的過(guò)程:
-
第一次揮手(FIN):
- 客戶端向服務(wù)器發(fā)送一個(gè)連接關(guān)閉請(qǐng)求,其中設(shè)置了FIN標(biāo)志位(FIN=1)。
- 客戶端不再發(fā)送數(shù)據(jù),但仍可以接收服務(wù)器發(fā)送的數(shù)據(jù)。
-
第二次揮手(ACK):
- 服務(wù)器收到客戶端的連接關(guān)閉請(qǐng)求后,回復(fù)一個(gè)確認(rèn)報(bào)文段作為回應(yīng)。
- 服務(wù)器在回復(fù)的報(bào)文段中設(shè)置了ACK標(biāo)志位(ACK=1),確認(rèn)客戶端的關(guān)閉請(qǐng)求。
- 服務(wù)器可能仍有數(shù)據(jù)要發(fā)送給客戶端,所以服務(wù)器的FIN標(biāo)志位尚未設(shè)置。
-
第三次揮手(FIN):
- 服務(wù)器繼續(xù)發(fā)送數(shù)據(jù)給客戶端,在數(shù)據(jù)發(fā)送完畢后,將自己的連接關(guān)閉請(qǐng)求發(fā)送給客戶端。
- 服務(wù)器設(shè)置FIN標(biāo)志位(FIN=1),表示服務(wù)器準(zhǔn)備關(guān)閉連接。
-
第四次揮手(ACK):
- 客戶端收到服務(wù)器的連接關(guān)閉請(qǐng)求后,回復(fù)一個(gè)確認(rèn)報(bào)文段作為回應(yīng)。
- 客戶端在回復(fù)的報(bào)文段中設(shè)置了ACK標(biāo)志位(ACK=1),確認(rèn)服務(wù)器的關(guān)閉請(qǐng)求。
- 至此,TCP連接正式關(guān)閉。
注意:在進(jìn)行四次揮手過(guò)程中,客戶端和服務(wù)器都可以在最后一次揮手前發(fā)送數(shù)據(jù),因?yàn)镕IN標(biāo)志位只表示自己不再發(fā)送數(shù)據(jù),而并不表示對(duì)方不再發(fā)送數(shù)據(jù)。因此,四次揮手可能是"FIN-WAIT-1",“FIN-WAIT-2”,"TIME-WAIT"等狀態(tài)之間的過(guò)程。等待一段時(shí)間后,處于TIME-WAIT狀態(tài)的一方會(huì)關(guān)閉連接,完成整個(gè)四次揮手過(guò)程。
為什么揮手需要四次
- 關(guān)閉連接時(shí),客戶端向服務(wù)端發(fā)送
FIN
時(shí),僅僅表示客戶端不再發(fā)送數(shù)據(jù)了但是還能接收數(shù)據(jù)。 - 服務(wù)端收到客戶端的
FIN
報(bào)文時(shí),先回一個(gè)ACK
應(yīng)答報(bào)文,而服務(wù)端可能還有數(shù)據(jù)需要處理和發(fā)送,等服務(wù)端不再發(fā)送數(shù)據(jù)時(shí),才發(fā)送FIN
報(bào)文給客戶端來(lái)表示同意現(xiàn)在關(guān)閉連接。
從上面過(guò)程可知,服務(wù)端通常需要等待完成數(shù)據(jù)的發(fā)送和處理,所以服務(wù)端的 ACK
和 FIN
一般都會(huì)分開(kāi)發(fā)送,因此是需要四次揮手。特定情況下,四次揮手是可以變成三次揮手的
第一次揮手丟失,會(huì)發(fā)生什么
會(huì)觸發(fā)超時(shí)重傳機(jī)制,客戶端重傳 FIN 報(bào)文,重發(fā)次數(shù)由 tcp_orphan_retries
參數(shù)控制。
第二次揮手丟失,會(huì)發(fā)生什么
客戶端就會(huì)觸發(fā)超時(shí)重傳機(jī)制,重傳 FIN 報(bào)文,直到收到服務(wù)端的第二次揮手,或者達(dá)到最大的重傳次數(shù)
第三次揮手丟失,會(huì)發(fā)生什么
服務(wù)端就會(huì)重發(fā) FIN 報(bào)文,重發(fā)次數(shù)仍然由 tcp_orphan_retrie
s 參數(shù)控制,這與客戶端重發(fā) FIN 報(bào)文的重傳次數(shù)控制方式是一樣的,F(xiàn)IN_WAIT_2狀態(tài),默認(rèn)60秒,有tcp_fin_timeout參數(shù)控制
第四次揮手丟失,會(huì)發(fā)生什么
如果第四次揮手的 ACK 報(bào)文沒(méi)有到達(dá)服務(wù)端,服務(wù)端就會(huì)重發(fā) FIN 報(bào)文,重發(fā)次數(shù)仍然由前面介紹過(guò)的 tcp_orphan_retries
參數(shù)控制
為什么TIME_WAIT等待時(shí)間是2MSL
MSL:報(bào)文最大生存時(shí)間
TTL:經(jīng)過(guò)路由跳數(shù)
TTL 的值一般是 64,Linux 將 MSL 設(shè)置為 30 秒,意味著 Linux 認(rèn)為數(shù)據(jù)報(bào)文經(jīng)過(guò) 64 個(gè)路由器的時(shí)間不會(huì)超過(guò) 30 秒,如果超過(guò)了,就認(rèn)為報(bào)文已經(jīng)消失在網(wǎng)絡(luò)中了。
? 網(wǎng)絡(luò)中可能存在來(lái)自發(fā)送方的數(shù)據(jù)包,當(dāng)這些發(fā)送方的數(shù)據(jù)包被接收方處理后又會(huì)向?qū)Ψ桨l(fā)送響應(yīng),所以一來(lái)一回需要等待 2 倍的時(shí)間TIME_WAIT等待時(shí)間為2倍的MSL(Maximum Segment Lifetime),這個(gè)值是為了確保在網(wǎng)絡(luò)中所有可能的冗余數(shù)據(jù)包都已經(jīng)被丟棄,從而保證TCP連接的可靠關(guān)閉。
為什么要有TIME_WAIT狀態(tài)
- 防止歷史連接中的數(shù)據(jù),被后面相同四元組的連接錯(cuò)誤的接收;
- 保證「被動(dòng)關(guān)閉連接」的一方,能被正確的關(guān)閉;
- 服務(wù)端在關(guān)閉連接之前發(fā)送的
SEQ = 301
報(bào)文,被網(wǎng)絡(luò)延遲了。 - 接著,服務(wù)端以相同的四元組重新打開(kāi)了新連接,前面被延遲的
SEQ = 301
這時(shí)抵達(dá)了客戶端,而且該數(shù)據(jù)報(bào)文的序列號(hào)剛好在客戶端接收窗口內(nèi),因此客戶端會(huì)正常接收這個(gè)數(shù)據(jù)報(bào)文,但是這個(gè)數(shù)據(jù)報(bào)文是上一個(gè)連接殘留下來(lái)的,這樣就產(chǎn)生數(shù)據(jù)錯(cuò)亂等嚴(yán)重的問(wèn)題。
TIME_WAIT 多有什么危害
- 第一是占用系統(tǒng)資源,比如文件描述符、內(nèi)存資源、CPU 資源、線程資源等;
- 第二是占用端口資源,端口資源也是有限的,一般可以開(kāi)啟的端口為
32768~61000
,也可以通過(guò)net.ipv4.ip_local_port_range
參數(shù)指定范圍。 - 如果客戶端(主動(dòng)發(fā)起關(guān)閉連接方)的 TIME_WAIT 狀態(tài)過(guò)多,占滿了所有端口資源,那么就無(wú)法對(duì)「目的 IP+ 目的 PORT」都一樣的服務(wù)端發(fā)起連接了,但是被使用的端口,還是可以繼續(xù)對(duì)另外一個(gè)服務(wù)端發(fā)起連接的
- 如果服務(wù)端(主動(dòng)發(fā)起關(guān)閉連接方)的 TIME_WAIT 狀態(tài)過(guò)多,并不會(huì)導(dǎo)致端口資源受限,因?yàn)榉?wù)端只監(jiān)聽(tīng)一個(gè)端口,而且由于一個(gè)四元組唯一確定一個(gè) TCP 連接,因此理論上服務(wù)端可以建立很多連接,但是 TCP 連接過(guò)多,會(huì)占用系統(tǒng)資源,比如文件描述符、內(nèi)存資源、CPU 資源、線程資源等
如何優(yōu)化 TIME_WAIT
-
打開(kāi) net.ipv4.tcp_tw_reuse 和 net.ipv4.tcp_timestamps 選項(xiàng);,tcp_tw_reuse 功能只能用客戶端(連接發(fā)起方),因?yàn)殚_(kāi)啟了該功能,在調(diào)用 connect() 函數(shù)時(shí),內(nèi)核會(huì)隨機(jī)找一個(gè) time_wait 狀態(tài)超過(guò) 1 秒的連接給新的連接復(fù)用,使用這個(gè)選項(xiàng),還有一個(gè)前提,需要打開(kāi)對(duì) TCP 時(shí)間戳的支持
-
net.ipv4.tcp_max_tw_buckets:這個(gè)值默認(rèn)為 18000,當(dāng)系統(tǒng)中處于 TIME_WAIT 的連接一旦超過(guò)這個(gè)值時(shí),系統(tǒng)就會(huì)將后面的 TIME_WAIT 連接狀態(tài)重置,這個(gè)方法比較暴力
-
程序中使用 SO_LINGER ,應(yīng)用強(qiáng)制使用 RST 關(guān)閉。我們可以通過(guò)設(shè)置 socket 選項(xiàng),來(lái)設(shè)置調(diào)用 close 關(guān)閉連接行為
優(yōu)化TIME_WAIT狀態(tài)主要是通過(guò)調(diào)整TCP連接的參數(shù)來(lái)減少或優(yōu)化TIME_WAIT等待時(shí)間,以減少資源占用和提高系統(tǒng)性能。以下是一些常見(jiàn)的優(yōu)化方法:
-
減少TIME_WAIT等待時(shí)間: 在Linux系統(tǒng)中,可以通過(guò)修改系統(tǒng)的TCP參數(shù)來(lái)減少TIME_WAIT等待時(shí)間。例如,可以通過(guò)修改
tcp_fin_timeout
參數(shù)來(lái)減少TIME_WAIT狀態(tài)的持續(xù)時(shí)間。這個(gè)參數(shù)控制在TCP連接關(guān)閉后,套接字保持在TIME_WAIT狀態(tài)的時(shí)間,默認(rèn)值是60秒??梢愿鶕?jù)實(shí)際情況適當(dāng)降低這個(gè)值,例如設(shè)置為30秒。 -
重用端口: 可以通過(guò)設(shè)置
SO_REUSEADDR
套接字選項(xiàng)來(lái)允許重用處于TIME_WAIT狀態(tài)的端口。這樣可以避免新的連接被拒絕,從而提高系統(tǒng)的連接處理能力。在Go語(yǔ)言中,可以通過(guò)設(shè)置ReuseAddr
字段為true
來(lái)實(shí)現(xiàn)端口重用:
listener, err := net.Listen("tcp", "localhost:8080")
if err != nil {
// 錯(cuò)誤處理
}
listener.(*net.TCPListener).SetReuseAddr(true)
-
快速回收: 在Linux系統(tǒng)中,可以通過(guò)設(shè)置
tcp_tw_recycle
參數(shù)來(lái)開(kāi)啟快速回收模式??焖倩厥漳J皆试S將處于TIME_WAIT狀態(tài)的套接字快速回收,從而釋放系統(tǒng)資源。但需要注意的是,快速回收模式可能會(huì)導(dǎo)致一些問(wèn)題,因此在開(kāi)啟前需要仔細(xì)評(píng)估網(wǎng)絡(luò)環(huán)境和應(yīng)用需求。
# 設(shè)置快速回收模式
sudo sysctl -w net.ipv4.tcp_tw_recycle=1
- 減少短暫連接: 盡量減少短暫連接的創(chuàng)建,短暫連接容易產(chǎn)生大量TIME_WAIT狀態(tài),增加系統(tǒng)負(fù)擔(dān)??梢酝ㄟ^(guò)連接池或連接復(fù)用的方式來(lái)優(yōu)化短暫連接的管理。
需要注意的是,優(yōu)化TIME_WAIT狀態(tài)需要根據(jù)具體的系統(tǒng)和網(wǎng)絡(luò)環(huán)境進(jìn)行調(diào)整,并且某些優(yōu)化方法可能會(huì)帶來(lái)潛在的風(fēng)險(xiǎn)。因此,在進(jìn)行優(yōu)化前應(yīng)該仔細(xì)評(píng)估系統(tǒng)的性能和穩(wěn)定性需求,并根據(jù)實(shí)際情況進(jìn)行調(diào)整。
服務(wù)器出現(xiàn)大量TIME_WAIT狀態(tài)的原因是什么
什么場(chǎng)景下服務(wù)端會(huì)主動(dòng)斷開(kāi)連接
- 第一個(gè)場(chǎng)景:HTTP 沒(méi)有使用長(zhǎng)連接
- 第二個(gè)場(chǎng)景:HTTP 長(zhǎng)連接超時(shí)
- 第三個(gè)場(chǎng)景:HTTP 長(zhǎng)連接的請(qǐng)求數(shù)量達(dá)到上限
服務(wù)器出現(xiàn)大量TIME_WAIT狀態(tài)的主要原因是短暫連接的頻繁建立和關(guān)閉,通常在高并發(fā)的網(wǎng)絡(luò)環(huán)境中或者存在大量短連接的場(chǎng)景下會(huì)出現(xiàn)這種情況。以下是一些導(dǎo)致服務(wù)器大量TIME_WAIT狀態(tài)的常見(jiàn)原因:
-
高并發(fā)連接: 當(dāng)服務(wù)器面對(duì)大量并發(fā)連接請(qǐng)求時(shí),每個(gè)連接建立后在關(guān)閉時(shí)會(huì)進(jìn)入TIME_WAIT狀態(tài)。如果連接的頻率很高,TIME_WAIT狀態(tài)的連接數(shù)量就會(huì)迅速增加。
-
短暫連接: 一些應(yīng)用或協(xié)議(如HTTP/1.0),特點(diǎn)是在每個(gè)請(qǐng)求完成后立即關(guān)閉連接,導(dǎo)致大量短暫連接產(chǎn)生。這些短暫連接會(huì)在關(guān)閉后進(jìn)入TIME_WAIT狀態(tài),從而積累大量TIME_WAIT連接。
-
連接重用不當(dāng): 如果服務(wù)器沒(méi)有正確地重用連接,而是頻繁地創(chuàng)建新的連接,就會(huì)導(dǎo)致大量TIME_WAIT狀態(tài)的連接堆積。在高并發(fā)場(chǎng)景下,應(yīng)盡量復(fù)用現(xiàn)有連接,避免頻繁創(chuàng)建和關(guān)閉連接。
-
服務(wù)器性能不足: 當(dāng)服務(wù)器的性能較低或網(wǎng)絡(luò)負(fù)載很高時(shí),處理連接的速度可能跟不上連接的建立和關(guān)閉速度,導(dǎo)致連接在TIME_WAIT狀態(tài)停留的時(shí)間較長(zhǎng)。
-
客戶端異常: 如果客戶端異常地關(guān)閉連接而沒(méi)有經(jīng)過(guò)正常的四次揮手過(guò)程,服務(wù)器可能會(huì)出現(xiàn)大量處于TIME_WAIT狀態(tài)的連接,因?yàn)榉?wù)器沒(méi)有收到客戶端的確認(rèn)。
為了解決大量TIME_WAIT狀態(tài)的問(wèn)題,可以考慮以下方法:
- 優(yōu)化服務(wù)器性能,提高服務(wù)器的處理能力和吞吐量,以便更快地處理連接的建立和關(guān)閉。
- 合理地設(shè)置TCP參數(shù),如
tcp_tw_reuse
和tcp_tw_recycle
等,根據(jù)實(shí)際情況減少TIME_WAIT等待時(shí)間。 - 優(yōu)化應(yīng)用程序邏輯,盡量復(fù)用連接,減少短暫連接的創(chuàng)建和關(guān)閉。
- 使用連接池或連接復(fù)用等技術(shù),合理管理連接資源。
服務(wù)器出現(xiàn)大量 CLOSE_WAIT 狀態(tài)的原因有哪些
當(dāng)服務(wù)端出現(xiàn)大量 CLOSE_WAIT 狀態(tài)的連接的時(shí)候,說(shuō)明服務(wù)端的程序沒(méi)有調(diào)用 close 函數(shù)關(guān)閉連接。當(dāng)服務(wù)端出現(xiàn)大量 CLOSE_WAIT 狀態(tài)的連接的時(shí)候,通常都是代碼的問(wèn)題,這時(shí)候我們需要針對(duì)具體的代碼一步一步的進(jìn)行排查和定位,主要分析的方向就是服務(wù)端為什么沒(méi)有調(diào)用 close
Socket編程
Socket編程是一種用于在計(jì)算機(jī)網(wǎng)絡(luò)中實(shí)現(xiàn)通信的編程方法。它是基于TCP/IP協(xié)議棧的一種編程接口,允許程序通過(guò)網(wǎng)絡(luò)在不同計(jì)算機(jī)之間進(jìn)行數(shù)據(jù)傳輸和通信。
在Socket編程中,程序可以通過(guò)創(chuàng)建Socket對(duì)象來(lái)建立網(wǎng)絡(luò)連接。Socket對(duì)象提供了一組函數(shù)(通常是系統(tǒng)調(diào)用)來(lái)進(jìn)行數(shù)據(jù)的發(fā)送和接收。通過(guò)Socket編程,程序可以實(shí)現(xiàn)客戶端和服務(wù)器之間的通信,實(shí)現(xiàn)數(shù)據(jù)的傳輸和交換。
Socket編程通常使用兩種類(lèi)型的Socket:
-
流式Socket(Stream Socket): 使用TCP協(xié)議來(lái)進(jìn)行數(shù)據(jù)傳輸,提供可靠的、面向連接的通信。流式Socket適用于需要可靠數(shù)據(jù)傳輸?shù)膱?chǎng)景,如HTTP、FTP等。
-
數(shù)據(jù)報(bào)Socket(Datagram Socket): 使用UDP協(xié)議來(lái)進(jìn)行數(shù)據(jù)傳輸,提供不可靠的、無(wú)連接的通信。數(shù)據(jù)報(bào)Socket適用于對(duì)數(shù)據(jù)傳輸時(shí)延要求較低,但可靠性要求較低的場(chǎng)景,如視頻流傳輸、實(shí)時(shí)游戲等。
Socket編程常用于網(wǎng)絡(luò)編程和分布式系統(tǒng)中,它允許不同計(jì)算機(jī)上的應(yīng)用程序之間進(jìn)行通信和數(shù)據(jù)交換,實(shí)現(xiàn)了跨網(wǎng)絡(luò)的數(shù)據(jù)傳輸和通信功能。在不同編程語(yǔ)言中,都提供了對(duì)Socket編程的支持,例如C、C++、Python、Java等。
- 服務(wù)端和客戶端初始化
socket
,得到文件描述符; - 服務(wù)端調(diào)用
bind
,將 socket 綁定在指定的 IP 地址和端口; - 服務(wù)端調(diào)用
listen
,進(jìn)行監(jiān)聽(tīng); - 服務(wù)端調(diào)用
accept
,等待客戶端連接; - 客戶端調(diào)用
connect
,向服務(wù)端的地址和端口發(fā)起連接請(qǐng)求; - 服務(wù)端
accept
返回用于傳輸?shù)?socket
的文件描述符; - 客戶端調(diào)用
write
寫(xiě)入數(shù)據(jù);服務(wù)端調(diào)用read
讀取數(shù)據(jù); - 客戶端斷開(kāi)連接時(shí),會(huì)調(diào)用
close
,那么服務(wù)端read
讀取數(shù)據(jù)的時(shí)候,就會(huì)讀取到了EOF
,待處理完數(shù)據(jù)后,服務(wù)端調(diào)用close
,表示連接關(guān)閉。
當(dāng)涉及到socket編程的面試題時(shí),面試官可能會(huì)問(wèn)一系列問(wèn)題來(lái)評(píng)估候選人的網(wǎng)絡(luò)編程能力。以下是一些常見(jiàn)的socket編程面試題及其答案:
什么是Socket
- 答案:Socket是一種用于實(shí)現(xiàn)網(wǎng)絡(luò)通信的編程接口,它允許進(jìn)程(程序)通過(guò)網(wǎng)絡(luò)進(jìn)行數(shù)據(jù)傳輸和通信。Socket提供了一種機(jī)制,使得不同主機(jī)上的進(jìn)程能夠建立連接并進(jìn)行數(shù)據(jù)交換。
TCP和UDP的區(qū)別
- 答案:TCP(傳輸控制協(xié)議)是一種面向連接的可靠協(xié)議,它通過(guò)三次握手來(lái)建立連接,并使用確認(rèn)和重傳機(jī)制來(lái)確保數(shù)據(jù)可靠傳輸。UDP(用戶數(shù)據(jù)報(bào)協(xié)議)是一種無(wú)連接的不可靠協(xié)議,它不進(jìn)行連接建立和斷開(kāi),直接將數(shù)據(jù)發(fā)送給目標(biāo),不保證數(shù)據(jù)的可靠傳輸。
socket()函數(shù)的作用
- 答案:socket()函數(shù)用于創(chuàng)建套接字,返回一個(gè)用于網(wǎng)絡(luò)通信的文件描述符。它需要指定通信協(xié)議(如TCP或UDP)和地址族(IPv4或IPv6)。
bind()函數(shù)的作用
- 答案:bind()函數(shù)用于將套接字與特定的IP地址和端口號(hào)綁定,使其能夠在網(wǎng)絡(luò)上被其他進(jìn)程找到。
listen和accept函數(shù)的區(qū)別
- 答案:listen()函數(shù)用于服務(wù)器端,將套接字設(shè)置為監(jiān)聽(tīng)模式,等待客戶端的連接請(qǐng)求。accept()函數(shù)用于服務(wù)器端,接受客戶端的連接請(qǐng)求,創(chuàng)建一個(gè)新的套接字用于與客戶端通信。
connect()函數(shù)的作用
- 答案:connect()函數(shù)用于客戶端,與服務(wù)器建立連接,發(fā)起與服務(wù)器的三次握手過(guò)程。
send()和recv()函數(shù)的區(qū)別
- 答案:send()函數(shù)用于發(fā)送數(shù)據(jù),recv()函數(shù)用于接收數(shù)據(jù)。send()函數(shù)返回發(fā)送的字節(jié)數(shù),recv()函數(shù)返回接收的字節(jié)數(shù)。
什么是阻塞和非阻塞socket
- 答案:阻塞socket在執(zhí)行讀寫(xiě)操作時(shí),會(huì)阻塞當(dāng)前進(jìn)程,直到操作完成或出現(xiàn)錯(cuò)誤。非阻塞socket在執(zhí)行讀寫(xiě)操作時(shí),不會(huì)阻塞當(dāng)前進(jìn)程,而是立即返回結(jié)果。
為什么TCP連接需要三次握手和四次揮手?
- 答案:三次握手用于確??蛻舳撕头?wù)器之間建立可靠的連接。四次揮手用于安全地關(guān)閉連接,確保雙方都能確認(rèn)對(duì)方的關(guān)閉意圖,并避免舊連接的混淆。
TIME_WAIT狀態(tài)的作用
- 答案:TIME_WAIT狀態(tài)用于確保在網(wǎng)絡(luò)中所有可能的冗余數(shù)據(jù)包都已經(jīng)被丟棄,從而保證TCP連接的可靠關(guān)閉。
如何優(yōu)化TIME_WAIT狀態(tài)
- 答案:可以通過(guò)減少TIME_WAIT等待時(shí)間、重用端口、設(shè)置快速回收模式等方法來(lái)優(yōu)化TIME_WAIT狀態(tài)。
這些問(wèn)題涵蓋了socket編程的一些基本概念、函數(shù)調(diào)用和網(wǎng)絡(luò)通信流程。面試時(shí),理解這些問(wèn)題的答案并能夠清晰地解釋socket編程的原理和用法,將有助于展示你的網(wǎng)絡(luò)編程能力和理解水平。
重傳機(jī)制
超時(shí)重傳
發(fā)送數(shù)據(jù)時(shí),會(huì)設(shè)定一個(gè)定時(shí)器,當(dāng)超過(guò)指定的時(shí)間后,沒(méi)有收到對(duì)方的ACK確認(rèn)應(yīng)答報(bào)文,就會(huì)重發(fā)數(shù)據(jù)
超時(shí)重傳的情況
- 數(shù)據(jù)包丟失
- 確認(rèn)應(yīng)答丟失
RTT:是數(shù)據(jù)發(fā)送時(shí)刻到接受到確認(rèn)的時(shí)刻的差值,也就是包的往返時(shí)間
超時(shí)重傳時(shí)間是以 RTO
(Retransmission Timeout 超時(shí)重傳時(shí)間)表示(超時(shí)重傳時(shí)間 RTO 的值應(yīng)該略大于報(bào)文往返 RTT 的值)
- 超時(shí)時(shí)間 RTO 較大時(shí),重發(fā)就慢,丟了老半天才重發(fā),沒(méi)有效率,性能差;
- 當(dāng)超時(shí)時(shí)間 RTO 較小時(shí),會(huì)導(dǎo)致可能并沒(méi)有丟就重發(fā),于是重發(fā)的就快,會(huì)增加網(wǎng)絡(luò)擁塞,導(dǎo)致更多的超時(shí),更多的超時(shí)導(dǎo)致更多的重發(fā)。
快速重傳
不以時(shí)間為驅(qū)動(dòng),而是以數(shù)據(jù)驅(qū)動(dòng)重傳
- 第一份 Seq1 先送到了,于是就 Ack 回 2;
- 結(jié)果 Seq2 因?yàn)槟承┰驔](méi)收到,Seq3 到達(dá)了,于是還是 Ack 回 2;
- 后面的 Seq4 和 Seq5 都到了,但還是 Ack 回 2,因?yàn)?Seq2 還是沒(méi)有收到;
- 發(fā)送端收到了三個(gè) Ack = 2 的確認(rèn),知道了 Seq2 還沒(méi)有收到,就會(huì)在定時(shí)器過(guò)期之前,重傳丟失的 Seq2。
- 最后,收到了 Seq2,此時(shí)因?yàn)?Seq3,Seq4,Seq5 都收到了,于是 Ack 回 6 。
所以,快速重傳的工作方式是當(dāng)收到三個(gè)相同的 ACK 報(bào)文時(shí),會(huì)在定時(shí)器過(guò)期之前,重傳丟失的報(bào)文段??焖僦貍鳈C(jī)制只解決了一個(gè)問(wèn)題,就是超時(shí)時(shí)間的問(wèn)題,但是還有另一個(gè)問(wèn)題,就是重傳的時(shí)候重傳一個(gè),還是所有。于是后面有了SACK
SACK(選擇性確認(rèn))
在TCP頭部選項(xiàng)字段里加一個(gè)SACK的東西,他可以將已收到的數(shù)據(jù)的信息發(fā)送給發(fā)送方,這樣發(fā)送方就知道哪些數(shù)據(jù)收到了,哪些沒(méi)有收到,就可以重傳丟失的數(shù)據(jù)
D-SACK
其主要使用了 SACK 來(lái)告訴「發(fā)送方」有哪些數(shù)據(jù)被重復(fù)接收了
好處:
- 可以讓「發(fā)送方」知道,是發(fā)出去的包丟了,還是接收方回應(yīng)的 ACK 包丟了;
- 可以知道是不是「發(fā)送方」的數(shù)據(jù)包被網(wǎng)絡(luò)延遲了;
- 可以知道網(wǎng)絡(luò)中是不是把「發(fā)送方」的數(shù)據(jù)包給復(fù)制了;
滑動(dòng)窗口
窗口大?。褐笩o(wú)需等待確認(rèn)應(yīng)答,而可以繼續(xù)發(fā)送數(shù)據(jù)的最大值
TCP頭部有個(gè)字段叫Window,也就是窗口的大小,這個(gè)字段是接收端告訴發(fā)送端自己還有多少緩沖區(qū)可以接收數(shù)據(jù)。于是發(fā)送端就可以根據(jù)這個(gè)接收端的處理能力來(lái)發(fā)送數(shù)據(jù),而不會(huì)導(dǎo)致接收端處理不過(guò)來(lái),通常窗口的大小是由接受方的窗口大小決定的。
發(fā)送方的窗口
- #1 是已發(fā)送并收到 ACK確認(rèn)的數(shù)據(jù):1~31 字節(jié)
- #2 是已發(fā)送但未收到 ACK確認(rèn)的數(shù)據(jù):32~45 字節(jié)
- #3 是未發(fā)送但總大小在接收方處理范圍內(nèi)(接收方還有空間):46~51字節(jié)
- #4 是未發(fā)送但總大小超過(guò)接收方處理范圍(接收方?jīng)]有空間):52字節(jié)以后
TCP滑動(dòng)窗口方案使用三個(gè)指針來(lái)跟蹤四個(gè)傳輸類(lèi)別中的每個(gè)類(lèi)別中的字節(jié)。其中兩個(gè)指針是絕對(duì)指針(指確定的序列號(hào)),一個(gè)是相對(duì)指針(需要做偏移)
-
SND.WND
:表示發(fā)送窗口的大?。ù笮∈怯山邮辗街付ǖ模?/li> -
SND.UNA
(Send Unacknoleged):是一個(gè)絕對(duì)指針,它指向的是已發(fā)送但未收到確認(rèn)的第一個(gè)字節(jié)的序列號(hào),也就是 #2 的第一個(gè)字節(jié) -
SND.NXT
:也是一個(gè)絕對(duì)指針,它指向未發(fā)送但可發(fā)送范圍的第一個(gè)字節(jié)的序列號(hào),也就是 #3 的第一個(gè)字節(jié) - 指向 #4 的第一個(gè)字節(jié)是個(gè)相對(duì)指針,它需要
SND.UNA
指針加上SND.WND
大小的偏移量,就可以指向 #4 的第一個(gè)字節(jié)了
那么可用窗口大小的計(jì)算就可以是:可用窗口大小 = SND.WND -(SND.NXT - SND.UNA)
接受方的窗口
- #1 + #2 是已成功接收并確認(rèn)的數(shù)據(jù)(等待應(yīng)用進(jìn)程讀?。?/li>
- #3 是未收到數(shù)據(jù)但可以接收的數(shù)據(jù);
- #4 未收到數(shù)據(jù)并不可以接收的數(shù)據(jù);
接收和發(fā)送窗口相等嗎
并不是完全相等,接收窗口的大小是約等于發(fā)送窗口的大小的。
因?yàn)榛瑒?dòng)窗口并不是一成不變的。比如,當(dāng)接收方的應(yīng)用進(jìn)程讀取數(shù)據(jù)的速度非??斓脑挘@樣的話接收窗口可以很快的就空缺出來(lái)。那么新的接收窗口大小,是通過(guò) TCP 報(bào)文中的 Windows 字段來(lái)告訴發(fā)送方。那么這個(gè)傳輸過(guò)程是存在時(shí)延的,所以接收窗口和發(fā)送窗口是約等于的關(guān)系。
流量控制
TCP 提供一種機(jī)制可以讓「發(fā)送方」根據(jù)「接收方」的實(shí)際接收能力控制發(fā)送的數(shù)據(jù)量,這就是所謂的流量控制。
TCP 流量控制是指通過(guò)一系列的機(jī)制來(lái)確保發(fā)送方與接收方之間的數(shù)據(jù)傳輸速率適應(yīng)接收方的處理能力,以防止過(guò)多的數(shù)據(jù)發(fā)送導(dǎo)致接收方無(wú)法及時(shí)處理而發(fā)生數(shù)據(jù)丟失或網(wǎng)絡(luò)擁塞的情況。
TCP流量控制的主要目標(biāo)
- 防止數(shù)據(jù)丟失和擁塞:如果發(fā)送方一次性發(fā)送大量數(shù)據(jù),可能會(huì)導(dǎo)致網(wǎng)絡(luò)擁塞,數(shù)據(jù)丟失或延遲增加。
- 適應(yīng)接收方速率:接收方可能處理數(shù)據(jù)的速度較慢,流量控制可以使發(fā)送方的速率適應(yīng)接收方的處理能力。
TCP 流量控制的主要機(jī)制是通過(guò)滑動(dòng)窗口(Sliding Window)和確認(rèn)機(jī)制來(lái)實(shí)現(xiàn)的。
TCP 流量控制的基本原理
- 滑動(dòng)窗口(Sliding Window): 發(fā)送方和接收方之間維護(hù)一個(gè)滑動(dòng)窗口,該窗口指示了接收方當(dāng)前能夠接受的數(shù)據(jù)量。發(fā)送方根據(jù)接收方報(bào)告的窗口大小來(lái)動(dòng)態(tài)調(diào)整發(fā)送數(shù)據(jù)的量,以保證不會(huì)超過(guò)接收方的處理能力。
- 確認(rèn)機(jī)制: 接收方會(huì)周期性地向發(fā)送方發(fā)送確認(rèn)(ACK)信息,表明接收方成功接收了某個(gè)特定序號(hào)的數(shù)據(jù)。發(fā)送方收到確認(rèn)后,會(huì)將對(duì)應(yīng)的數(shù)據(jù)序號(hào)從發(fā)送窗口中移除,從而允許發(fā)送新的數(shù)據(jù)。
TCP 流量控制實(shí)現(xiàn)的特性
- 滑動(dòng)窗口大小調(diào)整: 接收方可以根據(jù)自身的處理能力和緩沖區(qū)情況來(lái)動(dòng)態(tài)調(diào)整窗口大小。如果接收方的緩沖區(qū)還有空間,窗口會(huì)增大,允許發(fā)送更多數(shù)據(jù);如果緩沖區(qū)滿了,窗口會(huì)減小,限制發(fā)送數(shù)據(jù)的速率。
- 慢啟動(dòng)和擁塞避免: TCP 在建立連接時(shí)采用慢啟動(dòng)算法,初始窗口較小,然后逐漸增加發(fā)送窗口,以便探測(cè)網(wǎng)絡(luò)的擁塞情況。一旦網(wǎng)絡(luò)出現(xiàn)擁塞,TCP 會(huì)進(jìn)入擁塞避免狀態(tài),通過(guò)線性增加發(fā)送窗口來(lái)穩(wěn)定網(wǎng)絡(luò)擁塞情況。
- 超時(shí)重傳: 如果發(fā)送方?jīng)]有在一定時(shí)間內(nèi)收到接收方的確認(rèn),就會(huì)認(rèn)為數(shù)據(jù)丟失,觸發(fā)超時(shí)重傳機(jī)制,重新發(fā)送數(shù)據(jù)。這也有助于控制網(wǎng)絡(luò)擁塞情況。
TCP流量控制的過(guò)程
- 發(fā)送方發(fā)送數(shù)據(jù)段給接收方。
- 接收方接收數(shù)據(jù)并發(fā)送確認(rèn)。
- 發(fā)送方根據(jù)接收方發(fā)送的確認(rèn)來(lái)確定接收窗口的大小,確保發(fā)送數(shù)據(jù)的數(shù)量不會(huì)超過(guò)接收方的處理能力。
- 發(fā)送方還根據(jù)擁塞窗口的大小來(lái)控制發(fā)送速率,以避免網(wǎng)絡(luò)擁塞。
總之,TCP 流量控制確保了在發(fā)送方和接收方之間的數(shù)據(jù)傳輸速率匹配,從而保證了可靠的數(shù)據(jù)傳輸,避免了數(shù)據(jù)丟失和網(wǎng)絡(luò)擁塞問(wèn)題。
窗口關(guān)閉
如果窗口大小為 0 時(shí),就會(huì)阻止發(fā)送方給接收方傳遞數(shù)據(jù),直到窗口變?yōu)榉?0 為止,這就是窗口關(guān)閉。
那么,當(dāng)發(fā)生窗口關(guān)閉時(shí),接收方處理完數(shù)據(jù)后,會(huì)向發(fā)送方通告一個(gè)窗口非 0 的 ACK 報(bào)文,如果這個(gè)通告窗口的 ACK 報(bào)文在網(wǎng)絡(luò)中丟失了,那麻煩就大了。這會(huì)導(dǎo)致發(fā)送方一直等待接收方的非 0 窗口通知,接收方也一直等待發(fā)送方的數(shù)據(jù),如不采取措施,這種相互等待的過(guò)程,會(huì)造成了死鎖的現(xiàn)象。
如何解決窗口關(guān)閉潛在的死鎖問(wèn)題
為了解決這個(gè)問(wèn)題,TCP 為每個(gè)連接設(shè)有一個(gè)持續(xù)定時(shí)器,只要 TCP 連接一方收到對(duì)方的零窗口通知,就啟動(dòng)持續(xù)計(jì)時(shí)器。如果持續(xù)計(jì)時(shí)器超時(shí),就會(huì)發(fā)送窗口探測(cè) ( Window probe ) 報(bào)文,而對(duì)方在確認(rèn)這個(gè)探測(cè)報(bào)文時(shí),給出自己現(xiàn)在的接收窗口大小。
- 如果接收窗口仍然為 0,那么收到這個(gè)報(bào)文的一方就會(huì)重新啟動(dòng)持續(xù)計(jì)時(shí)器;
- 如果接收窗口不是 0,那么死鎖的局面就可以被打破了。
窗口探測(cè)的次數(shù)一般為 3 次,每次大約 30-60 秒(不同的實(shí)現(xiàn)可能會(huì)不一樣)。如果 3 次過(guò)后接收窗口還是 0 的話,有的 TCP 實(shí)現(xiàn)就會(huì)發(fā) RST
報(bào)文來(lái)中斷連接。
擁塞控制
為什么需要擁塞控制
盡管TCP已經(jīng)引入了流量控制機(jī)制來(lái)確保發(fā)送方不會(huì)以過(guò)快的速率向接收方發(fā)送數(shù)據(jù),但流量控制僅僅關(guān)注于發(fā)送方和接收方之間的數(shù)據(jù)傳輸。然而,網(wǎng)絡(luò)中的其他因素,如網(wǎng)絡(luò)擁塞、延遲、丟包等問(wèn)題,可能會(huì)影響整體的網(wǎng)絡(luò)性能和吞吐量。這就是為什么TCP還需要引入擁塞控制機(jī)制的原因。
擁塞窗口,和發(fā)送窗口有什么關(guān)系
擁塞窗口 cwnd是發(fā)送方維護(hù)的一個(gè)的狀態(tài)變量,它會(huì)根據(jù)網(wǎng)絡(luò)的擁塞程度動(dòng)態(tài)變化的。
我們?cè)谇懊嫣岬竭^(guò)發(fā)送窗口 swnd
和接收窗口 rwnd
是約等于的關(guān)系,那么由于加入了擁塞窗口的概念后,此時(shí)發(fā)送窗口的值是swnd = min(cwnd, rwnd),也就是擁塞窗口和接收窗口中的最小值。
擁塞窗口 cwnd
變化的規(guī)則:
- 只要網(wǎng)絡(luò)中沒(méi)有出現(xiàn)擁塞,
cwnd
就會(huì)增大; - 但網(wǎng)絡(luò)中出現(xiàn)了擁塞,
cwnd
就減少;
只要「發(fā)送方」沒(méi)有在規(guī)定時(shí)間內(nèi)接收到 ACK 應(yīng)答報(bào)文,當(dāng)發(fā)生了超時(shí)重傳,就會(huì)認(rèn)為網(wǎng)絡(luò)出了擁塞
擁塞控制的控制算法
慢啟動(dòng)
TCP剛開(kāi)始建立連接,一點(diǎn)一點(diǎn)發(fā)送數(shù)據(jù)包,當(dāng)發(fā)送方每收到一個(gè)ACK,擁塞控制cwnd的大小就會(huì)加1
有一個(gè)叫慢啟動(dòng)門(mén)限 ssthresh
(slow start threshold)狀態(tài)變量。
- 當(dāng)
cwnd
<ssthresh
時(shí),使用慢啟動(dòng)算法。 - 當(dāng)
cwnd
>=ssthresh
時(shí),就會(huì)使用「擁塞避免算法」。
擁塞避免
一般來(lái)說(shuō) ssthresh
的大小是 65535
字節(jié)。
那么進(jìn)入擁塞避免算法后,它的規(guī)則是:每當(dāng)收到一個(gè) ACK 時(shí),cwnd 增加 1/cwnd。
我們可以發(fā)現(xiàn),擁塞避免算法就是將原本慢啟動(dòng)算法的指數(shù)增長(zhǎng)變成了線性增長(zhǎng),還是增長(zhǎng)階段,但是增長(zhǎng)速度緩慢了一些。就這么一直增長(zhǎng)著后,網(wǎng)絡(luò)就會(huì)慢慢進(jìn)入了擁塞的狀況了,于是就會(huì)出現(xiàn)丟包現(xiàn)象,這時(shí)就需要對(duì)丟失的數(shù)據(jù)包進(jìn)行重傳。當(dāng)觸發(fā)了重傳機(jī)制,也就進(jìn)入了「擁塞發(fā)生算法」。
擁塞發(fā)生
當(dāng)發(fā)生了「超時(shí)重傳」,則就會(huì)使用擁塞發(fā)生算法。這個(gè)時(shí)候,ssthresh 和 cwnd 的值會(huì)發(fā)生變化:
-
ssthresh
設(shè)為cwnd/2
, -
cwnd
重置為1
(是恢復(fù)為 cwnd 初始化值,我這里假定 cwnd 初始化值 1)
當(dāng)發(fā)生了「快速重傳」,則就會(huì)使用擁塞發(fā)生算法。這個(gè)時(shí)候,ssthresh 和 cwnd 的值會(huì)發(fā)生變化:
-
cwnd = cwnd/2
,也就是設(shè)置為原來(lái)的一半; -
ssthresh = cwnd
; - 進(jìn)入快速恢復(fù)算法
快速恢復(fù)
進(jìn)入快速恢復(fù)算法如下:
- 擁塞窗口
cwnd = ssthresh + 3
( 3 的意思是確認(rèn)有 3 個(gè)數(shù)據(jù)包被收到了); - 重傳丟失的數(shù)據(jù)包;
- 如果再收到重復(fù)的 ACK,那么 cwnd 增加 1;
- 如果收到新數(shù)據(jù)的 ACK 后,把 cwnd 設(shè)置為第一步中的 ssthresh 的值,原因是該 ACK 確認(rèn)了新的數(shù)據(jù),說(shuō)明從 duplicated ACK 時(shí)的數(shù)據(jù)都已收到,該恢復(fù)過(guò)程已經(jīng)結(jié)束,可以回到恢復(fù)之前的狀態(tài)了,也即再次進(jìn)入擁塞避免狀態(tài);
半連接隊(duì)列和全連接隊(duì)列
在理解TCP半連接隊(duì)列(SYN隊(duì)列)和全連接隊(duì)列(Accept隊(duì)列)之前,讓我們先了解TCP的三次握手過(guò)程:
-
客戶端發(fā)送SYN(同步): 客戶端向服務(wù)器發(fā)送一個(gè)SYN包,表示客戶端想要建立連接。
-
服務(wù)器發(fā)送SYN + ACK: 服務(wù)器收到客戶端的SYN包后,會(huì)發(fā)送一個(gè)帶有ACK確認(rèn)號(hào)的SYN包作為響應(yīng),表示接受連接請(qǐng)求并準(zhǔn)備好建立連接。
-
客戶端發(fā)送ACK: 客戶端收到服務(wù)器的SYN + ACK包后,發(fā)送一個(gè)ACK包,表示確認(rèn)服務(wù)器的響應(yīng)。此時(shí)連接建立完成。
現(xiàn)在,我們可以來(lái)看看半連接隊(duì)列和全連接隊(duì)列:
-
半連接隊(duì)列(SYN隊(duì)列): 在TCP的三次握手過(guò)程中,當(dāng)服務(wù)器發(fā)送了SYN + ACK包后,它會(huì)等待客戶端發(fā)送最終的ACK包以完成連接的建立。在這個(gè)等待期間,服務(wù)器將客戶端的連接請(qǐng)求(即半連接)放入半連接隊(duì)列,等待客戶端的最終確認(rèn)。半連接隊(duì)列的大小通常是有限的,操作系統(tǒng)根據(jù)資源和配置來(lái)決定。
-
全連接隊(duì)列(Accept隊(duì)列): 一旦連接的三次握手完成,服務(wù)器將連接從半連接隊(duì)列移至全連接隊(duì)列。全連接隊(duì)列中的連接已經(jīng)建立并且可以開(kāi)始進(jìn)行數(shù)據(jù)傳輸。服務(wù)器將按順序從全連接隊(duì)列中選擇連接,并分配資源來(lái)處理這些連接。文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-643159.html
總結(jié)起來(lái),半連接隊(duì)列(SYN隊(duì)列)用于存放已經(jīng)發(fā)送了SYN請(qǐng)求但尚未完成三次握手的連接,而全連接隊(duì)列(Accept隊(duì)列)則存放已經(jīng)完成三次握手的連接,等待服務(wù)器分配資源來(lái)處理。這些隊(duì)列在TCP服務(wù)器中起著重要的作用,幫助管理并發(fā)連接并維護(hù)網(wǎng)絡(luò)性能。文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-643159.html
到了這里,關(guān)于計(jì)算機(jī)網(wǎng)絡(luò)—TCP的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!