自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

扒開TCP的“神秘外衣”,一文吃透它的本質(zhì)!

網(wǎng)絡 網(wǎng)絡管理
許多文件傳輸協(xié)議,如FTP(文件傳輸協(xié)議)、SFTP(安全文件傳輸協(xié)議)等,都是基于TCP 實現(xiàn)的 。

在如今這個信息爆炸的時代,網(wǎng)絡早已成為我們生活中不可或缺的一部分。無論是日常刷社交媒體、觀看視頻,還是進行在線辦公、購物,背后都離不開數(shù)據(jù)在網(wǎng)絡中的傳輸。而在這復雜的網(wǎng)絡世界里,有一位默默奉獻的 “明星”——TCP(Transmission Control Protocol),它在數(shù)據(jù)傳輸過程中扮演著舉足輕重的角色 。

想象一下,你在網(wǎng)上購買了一件心儀已久的商品,下單后,商家就像發(fā)送數(shù)據(jù)的源頭,而你則是接收數(shù)據(jù)的目的地。為了確保商品能準確無誤地送到你手中,就需要一個可靠的運輸系統(tǒng),這就好比網(wǎng)絡中的 TCP。TCP 就像是一位認真負責的快遞員,會確保數(shù)據(jù)從發(fā)送方準確、完整地抵達接收方,并且保證數(shù)據(jù)的順序正確,不會出現(xiàn)丟包、亂序的情況 。

從專業(yè)角度來講,TCP 是一種面向連接的、可靠的、基于字節(jié)流的傳輸層通信協(xié)議 。簡單來說,“面向連接” 意味著在數(shù)據(jù)傳輸之前,發(fā)送方和接收方需要先建立起一個連接,就像你要寄快遞,得先和快遞公司確定好收件人和寄件人的信息以及運輸路線;“可靠” 表示 TCP 會采取各種機制來保證數(shù)據(jù)的準確傳輸,如確認應答、重傳機制等;“基于字節(jié)流” 則是將數(shù)據(jù)看作是一連串的字節(jié)進行處理,而不是一個個獨立的數(shù)據(jù)包。

一、TCP協(xié)議概述

TCP(傳輸控制協(xié)議)是一種常用的網(wǎng)絡通信協(xié)議,它位于OSI模型的傳輸層。TCP提供可靠的、面向連接的數(shù)據(jù)傳輸服務。它通過使用序列號、確認應答和重傳機制,保證數(shù)據(jù)在網(wǎng)絡中的可靠傳輸。TCP還具有流量控制和擁塞控制功能,以確保發(fā)送方不會壓倒接收方和網(wǎng)絡。TCP協(xié)議是基于IP(Internet Protocol)協(xié)議之上構建的,它負責將應用程序分割成小塊(稱為報文段),并對這些報文段進行排序、重組和傳輸。

1.1 TCP歷史歷程

TCP 的誕生,就像是一部充滿傳奇色彩的科技史詩,它的出現(xiàn)徹底改變了網(wǎng)絡世界的格局 。故事要從20世紀60年代末講起,當時正處于美蘇冷戰(zhàn)時期,美國國防部為了在核戰(zhàn)爭威脅下確保通信的穩(wěn)定性,啟動了 ARPANET 項目 。這個項目旨在建立一個分散的、容錯性強的通信網(wǎng)絡,即使部分節(jié)點遭到破壞,網(wǎng)絡的其他部分仍能正常通信 。1969 年,ARPANET 的首批 4 個節(jié)點建立,分別位于 UCLA、斯坦福研究所、加州大學圣巴巴拉分校和猶他大學,這便是互聯(lián)網(wǎng)的雛形 。

隨著 ARPANET 的發(fā)展,網(wǎng)絡中的計算機數(shù)量不斷增加,不同類型的計算機和網(wǎng)絡之間需要一種統(tǒng)一的通信標準,TCP/IP 協(xié)議便應運而生 。1974 年,Vinton Cerf 和 Robert Kahn 發(fā)表了關于 TCP/IP 協(xié)議的論文,提出了一種新型的網(wǎng)絡互聯(lián)協(xié)議,奠定了 TCP/IP 協(xié)議的基礎 。他們就像是網(wǎng)絡世界的 “建筑師”,精心設計著 TCP/IP 協(xié)議這座宏偉的大廈 。TCP/IP 協(xié)議最初設計用于保證數(shù)據(jù)的可靠傳輸,它能夠處理數(shù)據(jù)的傳輸、路由和網(wǎng)絡連接等功能,其設計的彈性和可擴展性,使其能夠適應網(wǎng)絡的不斷發(fā)展和變化 。

在接下來的幾年里,TCP/IP 協(xié)議不斷完善和發(fā)展。1978 年,TCP/IP 協(xié)議首次被實驗性使用;1983 年 1 月 1 日,ARPANET 正式啟用了 TCP/IP 協(xié)議,標志著互聯(lián)網(wǎng)技術的正式成型 。這一天,就像是網(wǎng)絡世界的 “成人禮”,TCP/IP 協(xié)議從此成為互聯(lián)網(wǎng)的核心協(xié)議,開啟了互聯(lián)網(wǎng)發(fā)展的新紀元 。

此后,TCP/IP協(xié)議搭上了UNIX操作系統(tǒng)這輛 “快車”,很快推出了基于套接字(socket)的實際編程接口,這使得開發(fā)人員能夠更方便地利用TCP/IP協(xié)議進行網(wǎng)絡編程 。同時,TCP/IP 協(xié)議是免費或者少量收費的,這大大擴大了其使用人群 。這些因素共同作用,使得TCP/IP 協(xié)議逐漸成為全球范圍內(nèi)網(wǎng)絡通信的事實標準 。

1.2TCP協(xié)議特點

TCP 協(xié)議最主要的特點如下:

  • 面向連接:應用程序在使用 TCP 協(xié)議之前,必須先建立 TCP 連接。
  • 可靠性:TCP 提供可靠交付的服務。通過 TCP 連接傳送的數(shù)據(jù),無差錯、不丟失、不重復,并且按序到達。如果數(shù)據(jù)包丟失或出現(xiàn)差錯,則 TCP 負責重發(fā)數(shù)據(jù)。
  • 有序性:TCP 能夠把發(fā)送的數(shù)據(jù)劃分成一個個數(shù)據(jù)塊,編號后發(fā)送,接收方根據(jù)編號將這些數(shù)據(jù)塊組裝成完整的數(shù)據(jù)。因此,在接收端可以確保數(shù)據(jù)塊按照發(fā)送的順序進行組裝。
  • 流量控制:TCP 還提供了流量控制的功能,保證發(fā)送方的發(fā)送速度不會過快,導致接收方處理不及時,從而導致數(shù)據(jù)丟失。發(fā)送方會根據(jù)接收方返回的確認信息,調(diào)整自己的發(fā)送速度。
  • 擁塞控制:TCP 能夠根據(jù)網(wǎng)絡狀況調(diào)整傳輸數(shù)據(jù)的速率,防止出現(xiàn)擁塞。如果網(wǎng)絡出現(xiàn)擁塞,TCP 會通過降低發(fā)送方的數(shù)據(jù)傳輸速率和進行重傳等措施來保證數(shù)據(jù)的可靠傳輸。

1.3TCP常見問題解析

(1)什么是面向連接?

面向連接是一種網(wǎng)絡通信的方式,其中在通信前需要先建立一個雙方都認可的連接。在這個連接建立之后,通信的雙方可以進行數(shù)據(jù)傳輸。

面向連接的通信具有以下幾個特點:

  • 連接建立階段:通信的雙方首先要進行握手過程來建立連接,確保彼此能夠相互識別和確認。
  • 可靠性:在連接建立后,數(shù)據(jù)傳輸過程中會使用各種機制來確保數(shù)據(jù)的可靠性,如序列號、確認應答、重傳等。
  • 順序性:數(shù)據(jù)在傳輸過程中會按照發(fā)送順序進行傳遞,接收方能夠按照發(fā)送順序正確地接收和處理數(shù)據(jù)。
  • 面向字節(jié)流:面向連接的協(xié)議將數(shù)據(jù)視為連續(xù)的字節(jié)流,在發(fā)送端可能會對數(shù)據(jù)進行分割和組裝,在接收端則負責將字節(jié)流重新組裝成完整的數(shù)據(jù)。

常見的面向連接協(xié)議包括TCP(傳輸控制協(xié)議)和TLS(安全套接層協(xié)議),它們廣泛應用于互聯(lián)網(wǎng)通信、文件傳輸、電子郵件等場景。與之相對的是無連接通信,如UDP(用戶數(shù)據(jù)報協(xié)議),它不需要事先建立連接而直接進行數(shù)據(jù)傳輸。

舉例:就好比,你去醫(yī)院看病,如果是專家號,一般要提前預約,對只要預約(三次握手建立了連接)上了,你去了就不會看不上病,這是 TCP ;而如果你沒有預約,就直接跑過去,那不好意思,你只能看普通門診,而普通門診等的人很多,你就不一定能看得上病了。這是 UDP。既然是連接,必然是一對一的,就像繩子的兩端,所以 TCP 是一對一發(fā)送消息;而 UDP 協(xié)議不需要連接,可以一對一,也可以一對多,也可以多對多發(fā)送消息。

(2)什么是可靠的通信協(xié)議?

可靠的通信協(xié)議是指在數(shù)據(jù)傳輸過程中能夠確保數(shù)據(jù)的正確性、完整性和可達性的協(xié)議。它通過使用各種機制和算法來處理可能出現(xiàn)的錯誤、丟失、重復或亂序等問題,以保證數(shù)據(jù)能夠按照預期的方式傳輸?shù)侥繕说刂贰?/span>

以下是一些常見的用于實現(xiàn)可靠通信的機制和算法:

  • 序列號:發(fā)送方對每個發(fā)送的數(shù)據(jù)包進行編號,接收方按序接收并確認已接收的序列號,從而保證數(shù)據(jù)按正確順序傳遞。
  • 確認應答:接收方在成功接收到數(shù)據(jù)后向發(fā)送方發(fā)送確認消息,告知發(fā)送方數(shù)據(jù)已經(jīng)到達,若發(fā)送方未收到確認則進行重發(fā)。
  • 超時重傳:如果發(fā)送方在規(guī)定時間內(nèi)未收到確認應答,則會將該數(shù)據(jù)包視為丟失,并重新發(fā)送。
  • 滑動窗口:通過設置滑動窗口大小來控制發(fā)送方可以連續(xù)發(fā)送多少個數(shù)據(jù)包,在接收方按順序接收之前不斷向前滑動,以提高效率和吞吐量。
  • 錯誤檢測與糾正:利用校驗和、循環(huán)冗余檢測(CRC)等技術來檢測并修復傳輸中可能引入的錯誤。
  • 流量控制:通過控制發(fā)送方的發(fā)送速率,以避免接收方無法及時處理大量數(shù)據(jù)導致緩沖溢出。
  • 擁塞控制:根據(jù)網(wǎng)絡擁塞程度動態(tài)調(diào)整發(fā)送速率,防止網(wǎng)絡過載而導致數(shù)據(jù)丟失或延遲增加。

TCP 自身有三次握手和超時重傳等機制,所以無論網(wǎng)絡如何變化,主要不是主機宕機等原因都可以保證一個報文可以到達目標主機。

與之對比, UDP 就比較不負責任了,不管你收不收得到,反正我就無腦發(fā),網(wǎng)絡擁堵我也發(fā),它的職責是發(fā)出去。

(3)什么是面向字節(jié)流的?

面向字節(jié)流是一種通信模式,指的是數(shù)據(jù)在傳輸過程中被看作是連續(xù)的字節(jié)流,而不考慮數(shù)據(jù)之間的邊界。在這種模式下,發(fā)送方將數(shù)據(jù)按照字節(jié)序列發(fā)送,接收方則按照相同的順序接收和處理字節(jié)。

面向字節(jié)流的通信并不關心消息或數(shù)據(jù)包的邊界。它將數(shù)據(jù)切分為一個個字節(jié),并通過底層的傳輸協(xié)議(如TCP)將字節(jié)流逐個傳送給接收方。接收方根據(jù)自己定義的解析規(guī)則來處理這些字節(jié),并將它們組合成有意義的數(shù)據(jù)。

由于面向字節(jié)流不關心消息邊界,因此需要使用特定的機制來標識消息或數(shù)據(jù)包的開始和結(jié)束位置。常見的做法是在數(shù)據(jù)流中加入特殊字符或者長度信息來標識消息邊界。

面向字節(jié)流具有靈活性和可靠性,在實現(xiàn)上相對簡單,但同時也帶來了一些挑戰(zhàn),例如粘包(多個消息黏在一起)和拆包(一個消息被分割成多個部分)問題需要額外處理。

1.4TCP協(xié)議數(shù)據(jù)傳輸流程

TCP 協(xié)議的數(shù)據(jù)傳輸流程包括三個步驟:

建立連接(三次握手):

a. 客戶端發(fā)送一個SYN(同步)包給服務器,并設置初始序列號。

b. 服務器收到SYN包后,回復一個帶有確認碼和新的序列號的SYN-ACK(同步-確認)包。

c. 客戶端再次發(fā)送一個帶有確認碼和序列號的ACK(確認)包。

數(shù)據(jù)傳輸:

a. 連接建立后,客戶端可以開始發(fā)送數(shù)據(jù)。將數(shù)據(jù)分割成適當大小的段,并添加序列號。

b. 接收方會對每個收到的段進行確認,確保數(shù)據(jù)按正確順序到達,并且沒有丟失或損壞。

c. 如果發(fā)現(xiàn)丟失的段,接收方會請求發(fā)送方重新傳輸該段。

連接關閉:

a. 當發(fā)送方完成數(shù)據(jù)傳輸后,它會發(fā)送一個FIN(結(jié)束)包來關閉連接。

b. 接收方收到FIN包后,回復一個ACK確認。

c. 然后接收方也發(fā)送一個FIN包給發(fā)送方來關閉雙向連接。

d. 發(fā)送方回復一個ACK確認,最終連接關閉。

二、TCP協(xié)議的工作原理

TCP協(xié)議工作在OSI七層模型的第四層,即傳輸層。TCP協(xié)議通過三次握手建立連接,在連接建立后進行數(shù)據(jù)傳輸,并通過四次揮手關閉連接。

2.1tcp報文格式

①TCP報文是TCP層傳輸?shù)臄?shù)據(jù)單元,也叫報文段

圖片圖片

1、端口號:用來標識同一臺計算機的不同的應用進程。
1)源端口:源端口和IP地址的作用是標識報文的返回地址。
2)目的端口:端口指明接收方計算機上的應用程序接口。

TCP報頭中的源端口號和目的端口號同IP數(shù)據(jù)報中的源IP與目的IP唯一確定一條TCP連接。

②序號和確認號:是TCP可靠傳輸?shù)年P鍵部分。序號是本報文段發(fā)送的數(shù)據(jù)組的第一個字節(jié)的序號。在TCP傳送的流中,每一個字節(jié)一個序號。e.g.一個報文段的序號為300,此報文段數(shù)據(jù)部分共有100字節(jié),則下一個報文段的序號為400。所以序號確保了TCP傳輸?shù)挠行蛐?。確認號,即ACK,指明下一個期待收到的字節(jié)序號,表明該序號之前的所有數(shù)據(jù)已經(jīng)正確無誤的收到。確認號只有當ACK標志為1時才有效。比如建立連接時,SYN報文的ACK標志位為0。

③數(shù)據(jù)偏移/首部長度:4bits。由于首部可能含有可選項內(nèi)容,因此TCP報頭的長度是不確定的,報頭不包含任何任選字段則長度為20字節(jié),4位首部長度字段所能表示的最大值為1111,轉(zhuǎn)化為10進制為15,15*32/8 = 60,故報頭最大長度為60字節(jié)。首部長度也叫數(shù)據(jù)偏移,是因為首部長度實際上指示了數(shù)據(jù)區(qū)在報文段中的起始偏移值。

④保留:為將來定義新的用途保留,現(xiàn)在一般置0。

⑤控制位:URG ACK PSH RST SYN FIN,共6個,每一個標志位表示一個控制功能。

1)URG:緊急指針標志,為1時表示緊急指針有效,為0則忽略緊急指針。
2)ACK:確認序號標志,為1時表示確認號有效,為0表示報文中不含確認信息,忽略確認號字段。
3)PSH:push標志,為1表示是帶有push標志的數(shù)據(jù),指示接收方在接收到該報文段以后,
        應盡快將這個報文段交給應用程序,而不是在緩沖區(qū)排隊。
4)RST:重置連接標志,用于重置由于主機崩潰或其他原因而出現(xiàn)錯誤的連接?;蛘哂糜诰芙^非法的報文段和拒絕連接請求。
5)SYN:同步序號,用于建立連接過程,在連接請求中,SYN=1和ACK=0表示該數(shù)據(jù)段沒有使用捎帶的確認域,
        而連接應答捎帶一個確認,即SYN=1和ACK=1。
6)FIN:finish標志,用于釋放連接,為1時表示發(fā)送方已經(jīng)沒有數(shù)據(jù)發(fā)送了,即關閉本方數(shù)據(jù)流。

⑥窗口:滑動窗口大小,用來告知發(fā)送端接受端的緩存大小,以此控制發(fā)送端發(fā)送數(shù)據(jù)的速率,從而達到流量控制。窗口大小時一個16bit字段,因而窗口大小最大為65535。

⑦校驗和:奇偶校驗,此校驗和是對整個的 TCP 報文段,包括 TCP 頭部和 TCP 數(shù)據(jù),以 16 位字進行計算所得。由發(fā)送端計算和存儲,并由接收端進行驗證。

⑧緊急指針:只有當 URG 標志置 1 時緊急指針才有效。緊急指針是一個正的偏移量,和順序號字段中的值相加表示緊急數(shù)據(jù)最后一個字節(jié)的序號。TCP 的緊急方式是發(fā)送端向另一端發(fā)送緊急數(shù)據(jù)的一種方式。

⑨選項和填充:最常見的可選字段是最長報文大小,又稱為MSS(Maximum Segment Size),每個連接方通常都在通信的第一個報文段(為建立連接而設置SYN標志為1的那個段)中指明這個選項,它表示本端所能接受的最大報文段的長度。選項長度不一定是32位的整數(shù)倍,所以要加填充位,即在這個字段中加入額外的零,以保證TCP頭是32的整數(shù)倍。

⑩數(shù)據(jù)部分:TCP 報文段中的數(shù)據(jù)部分是可選的。在一個連接建立和一個連接終止時,雙方交換的報文段僅有 TCP 首部。如果一方?jīng)]有數(shù)據(jù)要發(fā)送,也使用沒有任何數(shù)據(jù)的首部來確認收到的數(shù)據(jù)。在處理超時的許多情況中,也會發(fā)送不帶任何數(shù)據(jù)的報文段。

2.2三次握手

(1)具體步驟拆解

在數(shù)據(jù)傳輸之前,TCP 需要在客戶端和服務器之間建立起可靠的連接,而這個建立連接的過程就像是一場精心編排的 “默契之舞”,被稱為三次握手 。接下來,我們就來詳細拆解一下這場 “舞蹈” 的每一個步驟 。

  • 第一次握手:客戶端向服務器發(fā)送一個 SYN(同步)報文,這個報文就像是客戶端向服務器發(fā)出的一個連接邀請 。報文中會包含客戶端隨機生成的初始序列號(Initial Sequence Number,ISN),假設這個序列號為 x 。此時,客戶端就像一個熱情的舞者,已經(jīng)做好了跳舞的準備,進入了 SYN_SEND 狀態(tài),滿懷期待地等待著服務器的回應 。這個初始序列號的作用就像是給數(shù)據(jù)傳輸這條 “項鏈” 上的每顆 “珠子”(數(shù)據(jù)字節(jié))都編上了號,以便后續(xù)接收方能夠正確地將它們串起來,保證數(shù)據(jù)的順序性 。
  • 第二次握手:服務器就像一位優(yōu)雅的舞者,收到客戶端的 SYN 報文后,會立即回應一個 SYN - ACK(同步確認)報文 。這個報文是服務器對客戶端邀請的回應,它包含兩部分重要信息 。一方面,服務器通過 ACK 標志位來確認收到了客戶端的 SYN 報文,確認號(Acknowledgment Number)設置為 x + 1,表示服務器期望下一次收到的序列號是 x + 1 。這就好比在舞會上,一方收到邀請后回應說:“我收到你的邀請啦,下一個動作就按這個順序來哦 。” 另一方面,服務器也會發(fā)送自己的 SYN 報文,帶上自己隨機生成的初始序列號,假設為 y 。這樣,服務器也準備好了跳舞,進入了 SYN_RECV 狀態(tài) 。
  • 第三次握手:客戶端收到服務器的 SYN - ACK 報文后,就像舞者確認了對方的舞蹈節(jié)奏和順序,會發(fā)送一個 ACK(確認)報文 。報文中的確認號設置為 y + 1,確認收到了服務器的 SYN 報文 。此時,客戶端和服務器就像兩位默契十足的舞者,已經(jīng)確定了彼此的節(jié)奏和順序,都進入了 ESTABLISHED 狀態(tài),成功建立了 TCP 連接,這場 “默契之舞” 也就圓滿完成了 。之后,它們就可以開始愉快地進行數(shù)據(jù)傳輸 “舞蹈表演” 了 。

(2)為什么是三次?

在了解了三次握手的具體步驟后,你可能會好奇,為什么建立連接偏偏需要三次握手呢?兩次不行嗎?四次會不會更保險呢?其實,三次握手背后蘊含著深刻的邏輯,是在可靠性和效率之間找到的最佳平衡點 。

我們先來看看兩次握手的情況 。如果只有兩次握手,客戶端發(fā)送 SYN 報文,服務器響應 ACK 報文 。表面上看,似乎雙方都表明了自己的態(tài)度,客戶端說 “我想和你建立連接”,服務器回答 “好呀” 。但實際上,這里存在很大的問題 。因為服務器發(fā)送ACK報文后,它并不知道客戶端是否能收到這個確認 。如果客戶端因為網(wǎng)絡問題沒有收到 ACK 報文,那么客戶端就會認為連接沒有建立成功,可能會再次發(fā)送 SYN 報文 。而服務器卻以為連接已經(jīng)建立,在那里干等著客戶端發(fā)送數(shù)據(jù),這就導致了服務器資源的浪費,而且還可能出現(xiàn)數(shù)據(jù)傳輸錯誤 。就好比兩個人約好見面,一個人說 “我在老地方等你”,另一個人回答 “我知道啦”,但如果回答的這個人聲音太小,對方?jīng)]聽見,那么第一個人可能會一直等下去,而第二個人卻不知道對方?jīng)]收到自己的回應,這就容易產(chǎn)生誤會 。

再說說四次握手 。從理論上來說,四次握手當然可以建立連接 。比如,客戶端發(fā)送 SYN 報文,服務器先回復 ACK 報文確認收到,然后再發(fā)送 SYN 報文,客戶端再回復 ACK 報文確認 。但這樣做會增加連接建立的時間和網(wǎng)絡開銷 。在如今這個追求高效的網(wǎng)絡時代,每一次額外的握手都會帶來一定的延遲,就像你去餐廳吃飯,服務員如果每做一個小步驟都要跟你確認一次,雖然很保險,但會讓你等得不耐煩 。而且,三次握手已經(jīng)足以保證雙方都能確認彼此的發(fā)送和接收能力,四次握手并沒有帶來實質(zhì)性的好處,反而有點 “畫蛇添足” 。

而三次握手就巧妙地解決了這些問題 。通過三次握手,客戶端和服務器都能確認對方的接收和發(fā)送能力 。第一次握手,客戶端發(fā)送 SYN 報文,證明客戶端的發(fā)送能力正常;第二次握手,服務器接收并回復 SYN - ACK 報文,證明服務器的接收和發(fā)送能力正常;第三次握手,客戶端接收并回復 ACK 報文,證明客戶端的接收能力正常 。這樣一來,雙方都清楚地知道對方已經(jīng)準備好了,而且避免了資源的浪費和不必要的延遲,就像兩個經(jīng)驗豐富的舞者,通過簡單而有效的溝通,迅速達成默契,開始精彩的舞蹈表演 。

2.3TCP的數(shù)據(jù)傳輸

應用層的數(shù)據(jù)放在write bytes中,通過應用程序?qū)rite bytes寫入TCP Send buffer,TCP Send buffer里面是以Segment的形式來存儲的,TCP進行發(fā)送的時候首先進行分段,數(shù)據(jù)發(fā)送出去后,接收方首先也會將接收到的這些段存儲到接收緩存區(qū)里,應用程序可以調(diào)用相關的函數(shù),從接收緩存區(qū)中將數(shù)據(jù)讀出來,讀到Read bytes里。數(shù)據(jù)在send buffer和receive buffer中都是以段的形式存儲的。

圖片圖片

⑴數(shù)據(jù)傳輸

發(fā)送方將數(shù)據(jù)發(fā)送出去后,會附有下次發(fā)送的序列號,而接收方會回應兩個比較重要的參數(shù),一個是回應值,另一個是提示窗口,來告訴發(fā)送方下一次可以發(fā)送多大的數(shù)據(jù)。

圖片圖片

現(xiàn)在我們以一個簡單的狀態(tài)機來看一下TCP的發(fā)送過程。在考慮簡單狀態(tài)機的時候,設定以下條件:單向傳輸過程,同時不考慮流量,也不考慮擁塞控制。

那對于TCP的發(fā)送方來講,應該有三個事件需要進行處理:

  • 當從應用程序中接收到要發(fā)送的數(shù)據(jù)后,進行創(chuàng)建分段。
  • 當發(fā)現(xiàn)某一個段的回應號超時,需要進行重傳,這是為了確保TCP的數(shù)據(jù)到達對方的一個方式。
  • 當看到對方回應ACK時,要對ACK進行處理,主要是看數(shù)據(jù)是否到達了對方。

⑵TCP的接收方對ACK的處理方式

圖片圖片

⑶TCP交互式數(shù)據(jù)傳輸

交互式數(shù)據(jù)傳輸最典型的一種應用就是Telnet,Telnet和Rlogin比較偏向發(fā)送交換式的數(shù)據(jù)。

圖片圖片

注意:ACK與下一段的數(shù)據(jù)一起發(fā)送。TCP會將ACK和數(shù)據(jù)封成一個包,也叫作delay ACK。

2.4TCP的四次揮手

當數(shù)據(jù)傳輸完成后,就像一場精彩的演出結(jié)束,客戶端和服務器需要優(yōu)雅地結(jié)束它們之間的 TCP 連接,這個過程被稱為四次揮手 。四次揮手的過程就像是兩個人告別時的禮貌對話,確保雙方都做好了結(jié)束交流的準備 。

圖片圖片

(1)揮手之前主動釋放連接的客戶端結(jié)束ESTABLISHED階段。

隨后開始“四次揮手”:

①首先客戶端想要釋放連接,向服務器端發(fā)送一段TCP報文,其中:標記位為FIN,表示“請求釋放連接“;序號為Seq=U;隨后客戶端進入FIN-WAIT-1階段,即半關閉階段。并且停止在客戶端到服務器端方向上發(fā)送數(shù)據(jù),但是客戶端仍然能接收從服務器端傳輸過來的數(shù)據(jù)。注意:這里不發(fā)送的是正常連接時傳輸?shù)臄?shù)據(jù)(非確認報文),而不是一切數(shù)據(jù),所以客戶端仍然能發(fā)送ACK確認報文。

②服務器端接收到從客戶端發(fā)出的TCP報文之后,確認了客戶端想要釋放連接,隨后服務器端結(jié)束ESTABLISHED階段,進入CLOSE-WAIT階段(半關閉狀態(tài))并返回一段TCP報文,其中:標記位為ACK,表示“接收到客戶端發(fā)送的釋放連接的請求”;序號為Seq=V;確認號為Ack=U+1,表示是在收到客戶端報文的基礎上,將其序號Seq值加1作為本段報文確認號Ack的值;隨后服務器端開始準備釋放服務器端到客戶端方向上的連接。客戶端收到從服務器端發(fā)出的TCP報文之后,確認了服務器收到了客戶端發(fā)出的釋放連接請求,隨后客戶端結(jié)束FIN-WAIT-1階段,進入FIN-WAIT-2階段前"兩次揮手"既讓服務器端知道了客戶端想要釋放連接,也讓客戶端知道了服務器端了解了自己想要釋放連接的請求。于是,可以確認關閉客戶端到服務器端方向上的連接了

③服務器端自從發(fā)出ACK確認報文之后,經(jīng)過CLOSED-WAIT階段,做好了釋放服務器端到客戶端方向上的連接準備,再次向客戶端發(fā)出一段TCP報文,其中:標記位為FIN,ACK,表示“已經(jīng)準備好釋放連接了”。注意:這里的ACK并不是確認收到服務器端報文的確認報文。序號為Seq=W;確認號為Ack=U+1;表示是在收到客戶端報文的基礎上,將其序號Seq值加1作為本段報文確認號Ack的值。隨后服務器端結(jié)束CLOSE-WAIT階段,進入LAST-ACK階段。并且停止在服務器端到客戶端的方向上發(fā)送數(shù)據(jù),但是服務器端仍然能夠接收從客戶端傳輸過來的數(shù)據(jù)。

④客戶端收到從服務器端發(fā)出的TCP報文,確認了服務器端已做好釋放連接的準備,結(jié)束FIN-WAIT-2階段,進入TIME-WAIT階段,并向服務器端發(fā)送一段報文,其中:標記位為ACK,表示“接收到服務器準備好釋放連接的信號”。序號為Seq=U+1;表示是在收到了服務器端報文的基礎上,將其確認號Ack值作為本段報文序號的值。確認號為Ack=W+1;表示是在收到了服務器端報文的基礎上,將其序號Seq值作為本段報文確認號的值。隨后客戶端開始在TIME-WAIT階段等待2MSL

(2)為什么客戶端發(fā)起了ack之后,服務端可以立馬關閉,而客戶端則要等待2MSL,才能進入關閉狀態(tài)呢。

要理解這個問題,首先我們需要弄清楚什么叫MSL。MSL是Maximum Segment Lifetime的英文縮寫,可譯為“最長報文段壽命”,它是任何報文在網(wǎng)絡上存在的最長的最長時間,超過這個時間報文將被丟棄,RFC793中規(guī)定MSL為2分鐘。要記住TCP是可靠的協(xié)議,之所以要有2MSL的等待,是因為端口是可以復用的,保證服務器已經(jīng)接收到來客戶端的ack,然后正常關閉服務器測的連接,要不復用端口的時候會對新的連接造成干擾。

為了更方便說明,我們先假設我們認同是2MSL是最保守可靠的方案,什么現(xiàn)象表明服務器已經(jīng)接收到了ack了,一個方法是服務器對于ack進行ack,客戶端就ack又ack,這樣子就無限循環(huán)了。還有一種就是TCP之所以可靠是因為還有針對唯有ack的數(shù)據(jù)段會有重發(fā)機制。所以如果服務器沒有關閉了沒有再次發(fā)送FIN請求,我們就基本可以假定服務器已經(jīng)收到了ack了,所以2MSL=FIN報文(來)+ack報文(去),當然也可以是2MSL=ack報文(去)+FIN報文(來),在2MSL的時間再也沒有收到服務器的fIN請求,所以我們可以認為服務已經(jīng)收到ack關閉連接了。

服務器端收到從客戶端發(fā)出的TCP報文之后結(jié)束LAST-ACK階段,進入CLOSED階段。由此正式確認關閉服務器端到客戶端方向上的連接??蛻舳说却?MSL之后,結(jié)束TIME-WAIT階段,進入CLOSED階段,由此完成“四次揮手”。后“兩次揮手”既讓客戶端知道了服務器端準備好釋放連接了,也讓服務器端知道了客戶端了解了自己準備好釋放連接了。于是,可以確認關閉服務器端到客戶端方向上的連接了,由此完成“四次揮手”。與“三次揮手”一樣,在客戶端與服務器端傳輸?shù)腡CP報文中,雙方的確認號Ack和序號Seq的值,都是在彼此Ack和Seq值的基礎上進行計算的,這樣做保證了TCP報文傳輸?shù)倪B貫性,一旦出現(xiàn)某一方發(fā)出的TCP報文丟失,便無法繼續(xù)"揮手",以此確保了"四次揮手"的順利完成。

“四次揮手”的通俗理解:

舉個栗子:把客戶端比作男孩,服務器比作女孩。通過他們的分手來說明“四次揮手”過程。

圖片圖片

“第一次揮手”:日久見人心,男孩發(fā)現(xiàn)女孩變成了自己討厭的樣子,忍無可忍,于是決定分手,隨即寫了一封信告訴女孩。“第二次揮手”:女孩收到信之后,知道了男孩要和自己分手,怒火中燒,心中暗罵:你算什么東西,當初你可不是這個樣子的!于是立馬給男孩寫了一封回信:分手就分手,給我點時間,我要把你的東西整理好,全部還給你!男孩收到女孩的第一封信之后,明白了女孩知道自己要和她分手。隨后等待女孩把自己的東西收拾好。“第三次揮手”:過了幾天,女孩把男孩送的東西都整理好了,于是再次寫信給男孩:你的東西我整理好了,快把它們拿走,從此你我恩斷義絕!“第四次揮手”:男孩收到女孩第二封信之后,知道了女孩收拾好東西了,可以正式分手了,于是再次寫信告訴女孩:我知道了,這就去拿回來!這里雙方都有各自的堅持。女孩自發(fā)出第二封信開始,限定一天內(nèi)收不到男孩回信,就會再發(fā)一封信催促男孩來取東西!男孩自發(fā)出第二封信開始,限定兩天內(nèi)沒有再次收到女孩的信就認為,女孩收到了自己的第二封信;若兩天內(nèi)再次收到女孩的來信,就認為自己的第二封信女孩沒收到,需要再寫一封信,再等兩天……

倘若雙方信都能正常收到,最少只用四封信就能徹底分手!這就是“四次揮手”。

(3)為什么“握手”是三次,“揮手”卻要四次?

TCP建立連接時之所以只需要"三次握手",是因為在第二次"握手"過程中,服務器端發(fā)送給客戶端的TCP報文是以SYN與ACK作為標志位的。SYN是請求連接標志,表示服務器端同意建立連接;ACK是確認報文,表示告訴客戶端,服務器端收到了它的請求報文。

即SYN建立連接報文與ACK確認接收報文是在同一次"握手"當中傳輸?shù)?,所?三次握手"不多也不少,正好讓雙方明確彼此信息互通。

TCP釋放連接時之所以需要“四次揮手”,是因為FIN釋放連接報文與ACK確認接收報文是分別由第二次和第三次"握手"傳輸?shù)摹楹谓⑦B接時一起傳輸,釋放連接時卻要分開傳輸?

建立連接時,被動方服務器端結(jié)束CLOSED階段進入“握手”階段并不需要任何準備,可以直接返回SYN和ACK報文,開始建立連接。釋放連接時,被動方服務器,突然收到主動方客戶端釋放連接的請求時并不能立即釋放連接,因為還有必要的數(shù)據(jù)需要處理,所以服務器先返回ACK確認收到報文,經(jīng)過CLOSE-WAIT階段準備好釋放連接之后,才能返回FIN釋放連接報文。

所以是“三次握手”,“四次揮手”。

三、TCP 協(xié)議的使用

3.1建立TCP連接

在C++中,可以使用Socket類來建立TCP連接。下面是一個簡單的示例代碼,展示了如何使用Socket類建立TCP連接的流程:

  1. 實例化 Socket 對象:可以使用帶有主機名和端口號參數(shù)的構造器來新建 Socket 對象。
  2. 建立連接:使用 Socket 類中的 connect() 方法來建立連接。
#include <iostream>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>

int main() {
    // 創(chuàng)建套接字
    int clientSocket = socket(AF_INET, SOCK_STREAM, 0);

    // 設置服務器地址和端口號
    struct sockaddr_in serverAddress;
    serverAddress.sin_family = AF_INET;
    serverAddress.sin_port = htons(8000); // 設置服務器端口號
    inet_pton(AF_INET, "127.0.0.1", &(serverAddress.sin_addr)); // 設置服務器地址

    // 建立連接
    if (connect(clientSocket, (struct sockaddr*)&serverAddress, sizeof(serverAddress)) < 0) {
        std::cerr << "Failed to connect to the server." << std::endl;
        return -1;
    }

    // 發(fā)送數(shù)據(jù)
    const char* message = "Hello, server!"; // 待發(fā)送的消息
    if (send(clientSocket, message, strlen(message), 0) < 0) {
        std::cerr << "Failed to send data to the server." << std::endl;
        return -1;
    }

    // 接收數(shù)據(jù)
    char buffer[1024];
    ssize_t bytesRead = recv(clientSocket, buffer, sizeof(buffer) - 1, 0);

  	if (bytesRead < 0) {
        std::cerr << "Failed to receive data from the server." << std::endl;
      	return -1;
  	}

  	buffer[bytesRead] = '\0';

  	std::cout << "Received: " << buffer << std::endl;

    // 關閉連接
    close(clientSocket);

    return 0;
}

在這個示例中,首先創(chuàng)建了一個客戶端套接字,然后設置服務器地址和端口號。之后使用connect()函數(shù)建立與服務器的連接;接下來,使用send()函數(shù)發(fā)送數(shù)據(jù)到服務器,并使用recv()函數(shù)從服務器接收數(shù)據(jù)。最后調(diào)用close()函數(shù)關閉連接。

3.2發(fā)送數(shù)據(jù)

在C++中,使用Socket類建立TCP連接后,可以通過send()函數(shù)向服務器發(fā)送數(shù)據(jù),而無需使用getOutputStream()方法。下面是一個示例代碼展示如何發(fā)送數(shù)據(jù)給服務器:

#include <iostream>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>

int main() {
    // 創(chuàng)建套接字
    int clientSocket = socket(AF_INET, SOCK_STREAM, 0);

    // 設置服務器地址和端口號
    struct sockaddr_in serverAddress;
    serverAddress.sin_family = AF_INET;
    serverAddress.sin_port = htons(8000); // 設置服務器端口號
    inet_pton(AF_INET, "127.0.0.1", &(serverAddress.sin_addr)); // 設置服務器地址

    // 建立連接
    if (connect(clientSocket, (struct sockaddr*)&serverAddress, sizeof(serverAddress)) < 0) {
        std::cerr << "Failed to connect to the server." << std::endl;
        return -1;
    }

    // 發(fā)送數(shù)據(jù)
    const char* message = "Hello, server!"; // 待發(fā)送的消息
    if (send(clientSocket, message, strlen(message), 0) < 0) {
        std::cerr << "Failed to send data to the server." << std::endl;
        return -1;
    }

	// ...

  	// 關閉連接
  	close(clientSocket);

  	return 0;
}

在這個示例中,通過調(diào)用send()函數(shù)將消息發(fā)送給服務器。你可以將要發(fā)送的數(shù)據(jù)存儲在一個字符數(shù)組或字符串中,并指定其長度作為第三個參數(shù)傳遞給send()函數(shù)。請確保在發(fā)送之前將數(shù)據(jù)轉(zhuǎn)換為適當?shù)母袷健?/span>

需要注意的是,這個示例僅展示了向服務器發(fā)送數(shù)據(jù)的部分,其他相關步驟(如建立連接、接收響應等)可以參考之前提供的代碼。同時,你可能需要根據(jù)具體情況進行適當?shù)腻e誤處理和異常處理。

3.3接收數(shù)據(jù)

在C++中,建立連接并接收從服務器返回的數(shù)據(jù)通常使用套接字(socket)和標準庫函數(shù)。不同于Java的Socket類,C++需要通過操作系統(tǒng)提供的底層API來進行網(wǎng)絡編程。

以下是一個簡單的示例代碼,展示如何使用C++中的socket和recv函數(shù)來接收服務器返回的數(shù)據(jù):

#include <iostream>
#include <sys/socket.h>
#include <arpa/inet.h>

int main() {
    // 創(chuàng)建套接字
    int sockfd = socket(AF_INET, SOCK_STREAM, 0);

    // 設置服務器地址
    struct sockaddr_in serverAddr{};
    serverAddr.sin_family = AF_INET;
    serverAddr.sin_port = htons(8000);  // 指定服務器端口號
    inet_pton(AF_INET, "127.0.0.1", &(serverAddr.sin_addr));  // 指定服務器IP地址

    // 連接到服務器
    connect(sockfd, (struct sockaddr*)&serverAddr, sizeof(serverAddr));

    // 接收從服務器返回的數(shù)據(jù)
    char buffer[1024];
    ssize_t bytesRead = recv(sockfd, buffer, sizeof(buffer) - 1, 0);

    if (bytesRead > 0) {
        buffer[bytesRead] = '\0';  // 添加字符串結(jié)束符

        std::cout << "Received data: " << buffer << std::endl;
    }

    // 關閉套接字
    close(sockfd);

    return 0;
}

在這個示例中,我們首先創(chuàng)建了一個套接字(sockfd),然后設置了服務器的地址信息,并調(diào)用connect函數(shù)與服務器建立連接。接著,我們使用recv函數(shù)來接收從服務器返回的數(shù)據(jù),并將其存儲在buffer中。最后,我們打印出接收到的數(shù)據(jù)并關閉套接字,需要注意的是,在實際應用中,你可能還需要進行錯誤處理和異常處理,并確保適當?shù)仃P閉套接字(socket)等資源。

3.4釋放連接

在C++中釋放連接通常使用socket和close函數(shù)來關閉套接字。

以下是一個簡單的示例代碼,展示如何在C++中釋放連接:

#include <iostream>
#include <sys/socket.h>
#include <arpa/inet.h>

int main() {
    // 創(chuàng)建套接字
    int sockfd = socket(AF_INET, SOCK_STREAM, 0);

    // 設置服務器地址
    struct sockaddr_in serverAddr{};
    serverAddr.sin_family = AF_INET;
    serverAddr.sin_port = htons(8000);  // 指定服務器端口號
    inet_pton(AF_INET, "127.0.0.1", &(serverAddr.sin_addr));  // 指定服務器IP地址

    // 連接到服務器
    connect(sockfd, (struct sockaddr*)&serverAddr, sizeof(serverAddr));

    // 發(fā)送數(shù)據(jù)或進行其他操作

    // 關閉套接字
    close(sockfd);

    return 0;
}

在這個示例中,在與服務器建立連接并完成相關操作后,我們調(diào)用close函數(shù)來關閉套接字(sockfd),以釋放連接資源。需要注意的是,釋放連接時應確保已經(jīng)完成了所有需要傳輸?shù)臄?shù)據(jù)或操作,并根據(jù)實際需求進行適當?shù)腻e誤處理和異常處理。

四、可靠傳輸:TCP 的 “看家本領”

4.1序列號與確認應答機制

在 TCP 的世界里,數(shù)據(jù)就像是一列有序的火車,而序列號則是給每節(jié)車廂(字節(jié))貼上的獨一無二的編號 。TCP 會為每個發(fā)送的字節(jié)都編上號,這樣接收方在收到數(shù)據(jù)后,就可以根據(jù)這些序列號來對數(shù)據(jù)進行排序,確保數(shù)據(jù)按序到達 。比如,你要發(fā)送一段包含 100 個字節(jié)的數(shù)據(jù),TCP 會從某個初始序列號開始,依次為這 100 個字節(jié)編號 。

而確認應答機制就像是接收方給發(fā)送方的 “小紙條”,用來告訴發(fā)送方哪些數(shù)據(jù)已經(jīng)成功接收 。當接收方收到數(shù)據(jù)后,會檢查數(shù)據(jù)的序列號,然后發(fā)送一個 ACK(確認)報文給發(fā)送方 。報文中的確認號(Acknowledgment Number)會設置為下一個期望接收的序列號 。例如,接收方收到了序列號為 1 - 100 的字節(jié),它會回復一個 ACK 報文,確認號設置為 101,表示它已經(jīng)成功接收了 1 - 100 的字節(jié),期望下一次收到序列號為 101 的字節(jié) 。通過這種方式,發(fā)送方就可以知道哪些數(shù)據(jù)已經(jīng)被接收,哪些還需要重發(fā) 。

4.2超時重傳機制

在網(wǎng)絡傳輸過程中,就像現(xiàn)實中的交通一樣,可能會出現(xiàn)各種意外情況,導致數(shù)據(jù)丟失或延遲 。超時重傳機制就是 TCP 應對這些情況的 “秘密武器” 。當發(fā)送方發(fā)送數(shù)據(jù)后,會啟動一個重傳定時器 。如果在規(guī)定的時間內(nèi)(這個時間被稱為超時重傳時間,Retransmission TimeOut,RTO)沒有收到接收方的 ACK 確認報文,發(fā)送方就會認為數(shù)據(jù)可能丟失了,于是重新發(fā)送這些數(shù)據(jù) 。

重傳定時器的作用就像是一個 “鬧鐘”,提醒發(fā)送方什么時候該重傳數(shù)據(jù) 。而這個 “鬧鐘” 的時間設置可不是固定不變的,它需要根據(jù)網(wǎng)絡狀況動態(tài)調(diào)整 。如果 RTO 設置得過大,發(fā)送方會等待很長時間才發(fā)現(xiàn)數(shù)據(jù)丟失,這會降低數(shù)據(jù)傳輸?shù)男?;如?RTO 設置得過小,發(fā)送方可能會頻繁重傳一些并沒有丟失的數(shù)據(jù),浪費網(wǎng)絡資源 。為了找到一個合適的 RTO 值,TCP 采用了自適應算法 。它會根據(jù)網(wǎng)絡的往返時間(Round - Trip Time,RTT),也就是數(shù)據(jù)從發(fā)送方到接收方再返回發(fā)送方所需要的時間,來動態(tài)調(diào)整 RTO 。比如,如果當前網(wǎng)絡比較擁堵,RTT 變長,TCP 就會相應地增大 RTO;如果網(wǎng)絡狀況良好,RTT 變短,RTO 也會隨之減小 。

4.3流量控制:避免 “交通堵塞”

在網(wǎng)絡傳輸中,發(fā)送方和接收方就像兩個不同速度的 “搬運工”,如果發(fā)送方發(fā)送數(shù)據(jù)的速度太快,而接收方處理數(shù)據(jù)的速度跟不上,就會像交通堵塞一樣,導致數(shù)據(jù)在接收方堆積,甚至丟失 。流量控制就是 TCP 為了避免這種情況而采取的措施,它通過滑動窗口機制來實現(xiàn) 。

滑動窗口機制就像是一個可伸縮的 “窗口”,控制著發(fā)送方和接收方之間的數(shù)據(jù)傳輸量 。接收方會根據(jù)自身的接收能力,在 ACK 報文中告訴發(fā)送方自己當前能夠接收的數(shù)據(jù)量,這個數(shù)據(jù)量就是接收窗口的大小 。發(fā)送方會根據(jù)接收方通告的接收窗口大小,來調(diào)整自己的發(fā)送窗口大小 。例如,接收方的接收窗口大小為 1000 字節(jié),發(fā)送方的發(fā)送窗口大小也會相應地設置為 1000 字節(jié),這意味著發(fā)送方最多可以連續(xù)發(fā)送 1000 字節(jié)的數(shù)據(jù)而不需要等待接收方的確認 。當接收方處理完一部分數(shù)據(jù)后,接收窗口會向前滑動,發(fā)送方也會根據(jù)新的接收窗口大小來調(diào)整自己的發(fā)送窗口,繼續(xù)發(fā)送數(shù)據(jù) 。這樣,就可以確保發(fā)送方發(fā)送數(shù)據(jù)的速度與接收方的接收能力相匹配,避免數(shù)據(jù)丟失和網(wǎng)絡擁塞 。

4.4擁塞控制:應對網(wǎng)絡 “大堵車”

擁塞控制是 TCP 為了應對網(wǎng)絡擁塞而采取的策略,就像是交通警察在道路擁堵時采取的疏導措施 。當網(wǎng)絡中出現(xiàn)擁塞時,路由器可能會丟棄數(shù)據(jù)包,導致發(fā)送方收不到 ACK 確認報文,從而觸發(fā)超時重傳 。而超時重傳又會進一步加重網(wǎng)絡擁塞,形成惡性循環(huán) 。為了打破這個循環(huán),TCP 采用了一系列擁塞控制算法 。

  1. 慢啟動:在 TCP 連接剛建立時,就像一輛剛啟動的汽車,發(fā)送方會以較小的擁塞窗口(通常為 1 個最大報文段長度,MSS)開始傳輸數(shù)據(jù) 。然后,每收到一個 ACK 確認報文,擁塞窗口就會增加 1 個 MSS 。這樣,擁塞窗口會以指數(shù)級的速度增長,逐漸探測網(wǎng)絡的擁塞情況 。就好比汽車剛啟動時,速度慢慢加快,觀察路況 。
  2. 擁塞避免:當擁塞窗口增長到一定程度(慢啟動門限,ssthresh)時,就進入了擁塞避免階段 。此時,擁塞窗口不再以指數(shù)級增長,而是每收到一個 ACK 確認報文,就增加 1/MSS 。這就像是汽車在路況良好時,保持穩(wěn)定的速度行駛 。通過這種線性增長的方式,避免網(wǎng)絡突然擁塞 。
  3. 快速重傳:如果接收方收到了失序的報文段,它會立即發(fā)送重復確認(對前面有序部分的確認),而不是等待自己發(fā)送數(shù)據(jù)時才捎帶確認 。當發(fā)送方連續(xù)收到三個重復確認時,就會知道中間有報文段丟失了,于是立即重傳丟失的報文段,而不是等待超時計時器超時后再重傳 。這就好比你發(fā)現(xiàn)快遞少了一件,馬上聯(lián)系商家補發(fā),而不是等很久才發(fā)現(xiàn) 。
  4. 快速恢復:當發(fā)送方收到三個重復確認,執(zhí)行快速重傳后,會進入快速恢復階段 。此時,慢啟動門限(ssthresh)會設置為當前擁塞窗口的一半,然后擁塞窗口會設置為慢啟動門限加上3個MSS(因為收到了三個重復確認,說明有三個數(shù)據(jù)報文段已經(jīng)離開了網(wǎng)絡,到達了接收方) 。之后,擁塞窗口會以線性增長的方式繼續(xù)調(diào)整,逐漸恢復到最佳的傳輸速率 。這就像是道路擁堵緩解后,汽車逐漸提速,但也不會一下子開得太快 。

通過這些擁塞控制算法,TCP 能夠根據(jù)網(wǎng)絡擁塞狀況動態(tài)調(diào)整發(fā)送速率,確保網(wǎng)絡的穩(wěn)定和高效運行 。

五、TCP 的應用場景

TCP 在我們的日常生活中無處不在,就像一個隱形的助手,默默地保障著各種網(wǎng)絡應用的穩(wěn)定運行 。下面,我們就來看看 TCP 在一些常見場景中的應用 。

5.1網(wǎng)頁瀏覽:讓世界觸手可及

當你在瀏覽器中輸入一個網(wǎng)址,然后輕松地瀏覽著豐富多彩的網(wǎng)頁時,背后離不開 TCP 的支持 。網(wǎng)頁瀏覽通常使用 HTTP(超文本傳輸協(xié)議)或 HTTPS(安全超文本傳輸協(xié)議),而這兩種協(xié)議都是基于 TCP 實現(xiàn)的 。比如,當你訪問淘寶的網(wǎng)站時,瀏覽器會作為客戶端,與淘寶的服務器建立 TCP 連接 。通過三次握手,雙方確認連接無誤后,瀏覽器向服務器發(fā)送 HTTP 請求,請求獲取網(wǎng)頁的內(nèi)容 。服務器接收到請求后,將網(wǎng)頁數(shù)據(jù)按照 TCP 協(xié)議的規(guī)則,分割成多個數(shù)據(jù)包,依次發(fā)送給瀏覽器 。

在這個過程中,TCP 的可靠傳輸機制確保了每個數(shù)據(jù)包都能準確無誤地到達瀏覽器 。如果某個數(shù)據(jù)包在傳輸過程中丟失,TCP 會通過重傳機制重新發(fā)送,保證網(wǎng)頁數(shù)據(jù)的完整性 。同時,TCP 的流量控制和擁塞控制機制會根據(jù)網(wǎng)絡狀況調(diào)整數(shù)據(jù)傳輸速度,避免網(wǎng)絡擁塞,讓你能夠快速、穩(wěn)定地加載網(wǎng)頁 。當你點擊網(wǎng)頁上的鏈接、查看圖片、觀看視頻時,每一次的數(shù)據(jù)請求和傳輸,都有 TCP 在背后保駕護航 。

5.2電子郵件:跨越時空的信息傳遞

電子郵件是我們?nèi)粘I詈凸ぷ髦谐S玫耐ㄐ欧绞街?,它的正常運行也依賴于 TCP 協(xié)議 。在電子郵件的發(fā)送過程中,發(fā)送方的郵件客戶端會與發(fā)送方的郵件服務器建立 TCP 連接,通過 SMTP(簡單郵件傳輸協(xié)議)將郵件發(fā)送到發(fā)送方的郵件服務器 。發(fā)送方的郵件服務器再通過 TCP 連接,將郵件轉(zhuǎn)發(fā)給接收方的郵件服務器 。接收方的郵件客戶端在需要接收郵件時,同樣會與接收方的郵件服務器建立 TCP 連接,使用 POP3(郵局協(xié)議版本 3)或 IMAP(互聯(lián)網(wǎng)郵件訪問協(xié)議)從郵件服務器獲取郵件 。

在這個過程中,TCP 確保了郵件在傳輸過程中的準確性和完整性 。想象一下,你給遠方的朋友發(fā)送一封重要的郵件,包含了一些珍貴的照片和文件 。如果沒有 TCP 的可靠傳輸機制,這些照片和文件可能會在傳輸過程中丟失或損壞,導致朋友無法正常接收 。而有了 TCP,你可以放心地發(fā)送郵件,不用擔心郵件會 “迷路” 或 “受傷” 。

5.3文件傳輸:大數(shù)據(jù)的穩(wěn)定搬運工

在網(wǎng)絡中傳輸文件時,我們希望文件能夠完整、準確地到達目的地,TCP 正好滿足了這一需求 。許多文件傳輸協(xié)議,如FTP(文件傳輸協(xié)議)、SFTP(安全文件傳輸協(xié)議)等,都是基于TCP 實現(xiàn)的 。以 FTP 為例,當你使用 FTP 客戶端上傳文件到 FTP 服務器時,首先會建立TCP連接 。連接建立后,客戶端和服務器之間會進行一系列的命令交互,確定傳輸?shù)奈募?、傳輸模式等信?。

然后,文件數(shù)據(jù)會被分割成多個TCP 數(shù)據(jù)包,在可靠傳輸機制的保障下,從客戶端傳輸?shù)椒掌?。同樣,在下載文件時,服務器也會通過TCP將文件數(shù)據(jù)準確地發(fā)送給客戶端 。比如,你要將一份大型的項目文檔上傳到公司的文件服務器,或者從服務器上下載一些重要的資料 。這些文件可能包含了大量的數(shù)據(jù),如果使用不可靠的傳輸方式,很容易出現(xiàn)數(shù)據(jù)丟失或錯誤的情況 。而 TCP 就像一個專業(yè)的搬運工,能夠穩(wěn)穩(wěn)地將文件從一端搬運到另一端,確保文件的完整性 。

責任編輯:武曉燕 來源: 深度Linux
相關推薦

2018-12-29 16:40:29

c語言編程語言指針

2021-03-28 20:44:34

Kafka中間件MQ

2020-12-29 08:02:37

SqlSession 程序Executor

2020-03-26 09:18:54

高薪本質(zhì)因素

2024-08-09 08:41:14

2021-10-29 11:30:31

補碼二進制反碼

2018-06-05 11:18:18

2024-08-26 08:58:50

2023-09-02 21:27:09

2020-09-27 08:02:47

操作系統(tǒng)

2023-08-27 21:02:14

2024-11-11 16:36:41

2021-04-27 11:28:21

React.t事件元素

2024-09-18 13:57:15

2021-08-06 09:36:00

TCPIP網(wǎng)絡協(xié)議

2020-10-29 08:55:04

微服務

2021-05-25 07:59:59

Linux運維Linux系統(tǒng)

2025-02-03 07:00:00

Java接口工具

2023-08-27 21:29:43

JVMFullGC調(diào)優(yōu)

2020-02-07 11:07:53

數(shù)組鏈表單鏈表
點贊
收藏

51CTO技術棧公眾號