在TCP/ip協議中,用源IP、源端口號、目的IP、目的端口號、協議號這樣一個五元組來標識一個通信!
端口號范圍劃分
- 0 - 1023: 知名端口號,HTTP,FTP,SSH 等這些廣為使用的應用層協議,他們的端口號都是固定的。
- 1024 - 65535: 操作系統動態分配的端口號。客戶端程序的端口號,就是由操作系統從這個范圍分配的。
認識知名端口號 (Well-Know Port Number)
有些服務器是非常常用的,為了使用方便,人們約定一些常用的服務器,都是用以下這些固定的端口號:
- ssh 服務器,使用 22 端口
- ftp 服務器,使用 21 端口
- telnet 服務器,使用 23 端口
- http 服務器,使用 80 端口
- https 服務器,使用 443
執行下面的命令,可以看到知名端口號
cat /etc/services
一個進程可以綁定多個端口號一個用來收數據一個用來傳數據;一個端口號不可以被多個進程綁定。
TCP(傳輸控制協議,Transmission Control Protocol )是一種位于傳輸層的通信協議。
應用場景
適用于對數據準確性、完整性、順序性要求高的場景 ,如文件傳輸(FTP 基于 TCP ) 、網頁瀏覽(HTTP 基于 TCP ) 、電子郵件(SMTP 基于 TCP ) 等。
TCP協議格式首部
- 源端口號(16 位):標識數據發送方應用程序端口,便于接收方后續回傳數據能找到對應端口 。比如客戶端瀏覽器發起 HTTP 請求,會用一個隨機的源端口號。
- 目的端口號(16 位):指明數據要抵達的目標應用程序端口,像 HTTP 協議默認目的端口號 80 ,用于定位 Web 服務器應用 。
- 序號(32 位):給 TCP 傳輸的每個字節編號,在建立連接和數據傳輸時,保證字節按序傳輸 。例如發送一篇長文檔,每個字節都有序號。
- 確認序號(32 位):接收方告知發送方下一個期望接收的字節序號,發送方依此判斷哪些數據已成功接收,哪些需重傳 。
- 首部長度(4 位):以 4 字節為單位指示首部長度,因首部中選項字段可變長,取值范圍對應 0 - 60 字節 ,無選項時通常為 20 字節 。
- 保留(6 位):預留字段,當前未使用,默認置 0 。
- 標志位(6 位):
- 窗口大小(16 位):這個窗口大小其實代表的是緩沖區里面剩余空間把它放在報頭里面目的是,想讓接收方得知目前傳送過去的數據,對方的接受速度是多少,來調整一下自己的發送速度(流量控制)。
- 檢驗和(16 位):對 TCP 首部、數據及偽首部計算校驗和,檢測傳輸過程中數據有無錯誤 。
- 緊急指針(16 位):當 URG 標志位為 1 時有效,指向緊急數據末尾,方便接收方優先處理緊急數據 。
選項與數據
- 選項:可選字段,長度可變,用于實現如最大段長度聲明、窗口擴大等擴展功能 。
- 數據:即有效載荷,承載應用層傳來的數據,TCP 負責可靠傳輸這部分數據 。
超時重傳機制:
如果你的數據發送過去后沒有得到應答,等到了一定時間就會重新補發,這個機制叫做超時重傳機制,這個時間是動態的,會根據你的網絡環境進行調整的,當你面臨的情況是應答丟失的時候,此時它主機b會得到兩個相同的數據,此時的主機b會進行去重操作,會根據你的報頭里面的32位序號進行查重去重!當你面臨的情況是始終重傳不成功,系統會認為你的網絡出現了異常,會自動斷開兩個主機的連接!
面對主機B收到重復的信息,此時操作系統可以根據報文里面的序號,進行去重操作!
TCP 連接管理機制詳解
TCP 連接管理主要包括建立連接和斷開連接兩個過程,分別通過三次握手和四次揮手實現。
TCP的三次握手:剛開始客戶端進行了connect在客戶端狀態沒有變為ESTABLISHED之前一直處于阻塞狀態,第一次握手是客戶端給服務器發送的報文是SYN類型的(申請建立連接)此時的客戶端狀態為SYN_SENT,當你服務器收到發來的申請后狀態變為SYN_RCVD,然后向客戶端發送SYN+ACK(申請建立連接和確認收到了客戶端發來的SYN)這是第二次握手,當客戶端收到了來自服務器的應答后狀態變為ESTABLISHED,隨后向服務器發送ACK(確認自己收到了應答),收到信息后的服務器狀態變為ESTABLISHED,此時的服務器會把剛剛完成三次握手后分配到的新的連接fd,交給accept,第三次握手的時候其實是已經可以攜帶數據了,做出捎帶應答!
建立連接以后的通信:所用到的write和read其實都是面向發送緩沖區和接受緩沖區進行操作的!
TCP四次揮手:第一次揮手是客戶端給服務器發FIN,客戶端的狀態變為FIN_WAIT_1,服務器接受到了以后狀態變為CLOSE_WAIT,第二次揮手然后給客戶端發送ACK應答,接收到信息的客戶端狀態變為FIN_WAIT_2,第三次揮手緊接著服務器會向客戶端發送FIN,狀態變為LAST_ACK,客戶端收到斷開連接請求以后狀態變為TIME_WAIT,第四次揮手就是客戶端給服務器的應答,狀態變為CLOSED!
解決疑問:
至少三次握手是因為:1.客戶端和服務端各自都要至少進行一次收報文和發報文,這樣其實可靠驗證了全雙工通路是否通暢!!!2.奇數次握手,在一般情況,握手失敗的連接成本嫁接給了客戶端!
為什么兩次不行是因為:當你服務器再發回給客戶端的信息,你并不能知道客戶端到底有沒有收到!
為什么一次不行是因為:會發生SYN洪水,直到服務器內存不夠分配的時候會導致服務中斷!
插入知識點:SYN洪水:
SYN洪水不止一次握手會出現:SYN 洪水(SYN Flood)是一種常見的 DoS(Denial of Service,拒絕服務)攻擊手段,它利用了 TCP 協議在建立連接時三次握手的漏洞來實施攻擊,以下是關于 SYN 洪水攻擊的詳細介紹:
攻擊原理
正常情況下,TCP 建立連接需要經過三次握手。客戶端發送 SYN 包請求建立連接,服務器收到后回復 SYN + ACK 包并分配資源等待客戶端的 ACK 包完成連接建立。而 SYN 洪水攻擊中,攻擊者會偽造大量源 IP 地址,向目標服務器發送大量的 SYN 包。服務器收到這些請求后,會為每個請求分配資源并發送 SYN + ACK 包進行響應,然后等待客戶端的 ACK 包。由于攻擊者使用的是偽造的 IP 地址,服務器無法收到這些偽造客戶端的 ACK 確認,會不斷重傳 SYN + ACK 包,并長時間保留這些半連接狀態的資源,直到超時。當服務器的半連接隊列被填滿后,就無法再處理正常用戶的連接請求,導致正常用戶無法與服務器建立連接,從而實現拒絕服務的目的。
防范措施
- 防火墻配置:通過防火墻設置規則,限制來自同一 IP 地址的 SYN 請求速率,防止單個 IP 地址發送過多的 SYN 包。
- TCP SYN Cookie 技術:服務器在收到 SYN 包時,不立即分配資源,而是根據 SYN 包的信息生成一個特殊的 Cookie(一種加密的序列號),并將其包含在 SYN + ACK 包中發送給客戶端。當客戶端返回 ACK 包時,服務器根據 ACK 包中的信息驗證 Cookie 的有效性,如果驗證通過,則建立連接。這樣可以避免服務器為大量偽造的 SYN 請求分配資源。
- 增加服務器資源:增加服務器的內存、CPU 等資源,提高服務器的處理能力和抗攻擊能力。
- 入侵檢測系統(IDS)/ 入侵防御系統(IPS):部署 IDS/IPS 系統,實時監測網絡流量,檢測并阻止 SYN 洪水攻擊。
從這個攻擊原理其實可以明白:在三次握手中最怕的一次握手是第三次客戶端給服務器的應答ACK,假如你是只有兩次握手,那你的第二次握手丟失以后整個壓力就會給到服務端,導致服務崩潰,但是如果你是三次握手,就不是這樣,因為如果丟失了第三次握手,整個壓力就會給到客戶端上,這樣就能保證服務器的穩定性!
四次揮手原因:
它不進行捎帶應答是因為服務器與客戶端進行關閉通信的時候存在著“協商”!
- TCP 協議規定,主動關閉連接的一方要處于 TIME_WAIT 狀態,等待兩個 MSL (maximum segment lifetime) 的時間后才能回到 CLOSED 狀態。
- 我們使用 Ctrl - C 終止了 server,所以 server 是主動關閉連接的一方,在 TIME_WAIT 期間仍然不能再次監聽同樣的 server 端口;
為了避免這種情況,所以可以去用setsockopt。
- MSL 在 RFC1122 中規定為兩分鐘,但是各操作系統的實現不同,在 Centos7 上默認配置的值是 60s;
- 可以通過
cat /proc/sys/net/ipv4/tcp_fin_timeout
查看 msl 的值; - 規定 TIME_WAIT 的時間請讀者參考 UNP 2.7 節;
MSL:一個報文它在網絡中存活的時間是有限的!
當你第三次揮手結束,如果第四次揮手丟失,導致服務端收不到最后的一個ACK,此時Time_wait的時間可以讓服務端端有足夠的時間去補發一個FIN!等待時間一般為兩個MSL(在傳輸過程中最大存在時長,這個一般是不確定的,因為如果遇到一個阻塞,那存在時長就大了)
流量控制:
接收端處理數據的速度是有限的。如果發送端發的太快,導致接收端的緩沖區被打滿,這個時候如果發送端繼續發送,就會造成丟包,繼而引起丟包重傳等一系列連鎖反應。
因此 TCP 支持根據接收端的處理能力,來決定發送端的發送速度。這個機制就叫做流量控制 (Flow Control):
- 接收端將自己可以接收的緩沖區大小放入 TCP 首部中的 “窗口大小” 字段,通過 ACK 端通知發送端;
- 窗口大小字段越大,說明網絡的吞吐量越高;
- 接收端一旦發現自己的緩沖區快滿了,就會將窗口大小設置成一個更小的值通知給發送端;
- 發送端接收到這個窗口之后,就會減慢自己的發送速度;
- 如果接收端緩沖區滿了,就會將窗口置為 0;這時發送方不再發送數據,但是需要定期發送一個窗口探測數據段,使接收端把窗口大小告訴發送端。
流量控制屬于可靠性還是效率?可靠性!
滑動窗口:
剛才我們討論了確認應答策略,對每一個發送的數據段,都要給一個 ACK 確認應答。收到 ACK 后再發送下一個數據段。
這樣做有一個比較大的缺點,就是性能較差,尤其是數據往返的時間較長的時候。
滑動窗口的大小,根據接受方緩沖區的剩余大小進行調整,這樣可以保證滑動窗口里面的數據一次性傳給接收方不會導致數據丟包!
關于緩沖區:
TCP 協議依靠發送緩沖區來保存已經發出但未收到應答的報文 。具體如下:
- 緩沖區劃分:發送緩沖區通常分為三部分。已發送已確認的數據,這部分數據傳輸已完成,可被后續數據覆蓋;已發送未確認的數據,即暫時保存等待應答的報文所在區域,這部分區域也屬于滑動窗口范疇,其最大范圍由對方接收窗口大小決定 ;未發送未確認的數據,是等待發送且未得到接收方接收許可的數據。通過設置指針(如指向窗口開始和結束的指針)或數字下標來區分這些區域,隨著數據發送和確認,指針移動實現窗口滑動 。
- 保存作用:發送緩沖區保存已發送未確認報文,是為實現可靠傳輸。若發送方在一定時間(由超時重傳時間 RTO 決定 )內未收到接收方對應答報文的確認,就會從發送緩沖區取出對應報文副本重傳 。 比如網絡擁塞導致報文丟失或延遲到達接收方,接收方無法及時返回確認,發送方超時后從緩沖區取出報文重發,保障數據最終能送達接收方。 同時,滑動窗口機制也基于發送緩沖區這些劃分來控制數據發送速率,避免接收方處理不過來。
傳輸異常處理:
若窗口更新通知在傳輸途中丟失,發送主機 A 無法得知接收主機 B 窗口狀態變化,會導致通信受阻。此時,發送主機 A 會定時發送窗口探測包,來主動獲取窗口信息,以便恢復數據傳輸。
滑動窗口機制通過動態調整窗口大小,在保障數據可靠傳輸的同時,還能適應網絡和接收端的不同狀態,有效提升網絡傳輸效率,避免網絡擁塞和數據丟失。
注意:快重傳并不是超時重傳機制!超重傳機制可以理解為是兜底的,而快重傳是提高效率的!
快重傳機制是 TCP 協議中用于快速檢測并恢復丟失數據包的機制 。當接收方收到亂序數據包時,會立即向發送方發送重復確認 。當發送方累計收到三個相同的重復確認時,就會判定對應的數據包已丟失,不等重傳超時,直接重傳該數據包 。比如發送方發送數據包 1、2、3、4 ,若數據包 2 丟失,接收方收到 1、3、4 后發送重復確認,發送方收到三個重復確認,就快速重傳數據包 2 。該機制減少了網絡傳輸延遲,提升了 TCP 協議在網絡傳輸中的效率和可靠性 。
延遲應答
如果接收數據的主機立刻返回 ACK 應答,這時候返回的窗口可能比較小。
- 假設接收端緩沖區為 1M,一次收到了 500K 的數據;如果立刻應答,返回的窗口就是 500K;
- 但實際上可能處理端處理的速度很快,10ms 之內就把 500K 數據從緩沖區消費掉了;
- 在這種情況下,接收端處理還遠沒有達到自己的極限,即使窗口再放大一些,也能處理過來;
- 如果接收端稍微等一會再應答,比如等待 200ms 再應答,那么這個時候返回的窗口大小就是 1M;
一定要記得,窗口越大,網絡吞吐量就越大,傳輸效率就越高。我們的目標是在保證網絡不擁塞的情況下盡量提高傳輸效率;
那么所有的包都可以延遲應答么?肯定也不是;
- 數量限制:每隔 N 個包就應答一次;
- 時間限制:超過最大延遲時間就應答一次;
擁塞控制
雖然 TCP 有了滑動窗口這個大殺器,能夠高效可靠的發送大量的數據。但是如果在剛開始階段就發送大量的數據,仍然可能引發問題。
因為網絡上有很多的計算機,可能當前的網絡狀態就已經比較擁堵。在不清楚當前網絡狀態下,貿然發送大量的數據,是很有可能引起雪上加霜的。
TCP 引入慢啟動機制,先發少量的數據,探探路,摸清當前的網絡擁堵狀態,再決定按照多大的速度傳輸數據。
一個主機緩解不了網絡擁塞,但是一群主機就可以緩解了!
看下圖分析:
慢啟動
TCP 啟動時,擁塞窗口(cwnd)初始值通常為 1 ,慢啟動閾值(ssthresh)等于窗口最大值(如初始值為 16 ) 。在慢開始階段,cwnd 按指數規律增長。每收到一個確認應答,cwnd 就增加 1 。這使得發送方發送的數據量迅速增加,網絡吞吐量逐漸上升。例如,從傳輸輪次 0 開始,cwnd 從 1 逐步增長,快速提升數據發送量。
擁塞避免
當 cwnd 增長到慢啟動閾值(如達到 16 )后,進入擁塞避免階段。此時,cwnd 不再按指數增長,而是采用 “加法增大” 策略,即每收到一個確認應答,cwnd 增加一個較小的固定值(如 1 ) 。這種方式讓發送方數據發送量緩慢、平穩增加,防止網絡因發送數據量增長過快而擁塞。
網絡擁塞處理
若出現大量丟包,判定為網絡擁塞。此時采取 “乘法減小” 策略,ssthresh 值變為原來的一半(如從 16 變為 12 ) ,同時 cwnd 置回 1 ,重新進入慢開始階段。這能迅速降低發送方數據發送量,緩解網絡擁塞。少量丟包時,僅觸發超時重傳,不調整 ssthresh 和 cwnd 。
TCP 擁塞控制機制在追求快速數據傳輸的同時,平衡網絡負載,避免擁塞,就像熱戀中把握節奏,既積極又不過度,保障網絡通信順暢。
TCP是面向字節流:
面向字節流:讀和寫不需要匹配。TCP是面向字節流,UDP面向數據報,udp寫一次就得讀一次!
粘包問題:說簡單就是,不知道一段報文從哪開始到哪結束,從而導致讀取報文錯誤!
TCP異常情況:
當你的進程終止的時候(無論是客戶端還是服務端或者兩個同時),此時我們應該知道linux下一切皆文件,包括通信。有因為文件的生命周期是隨進程的,所以進程終止了,通信也要結束了,此時通信進行正常的四次揮手既可!