網絡知識


網絡知識

1. 請詳細介紹下TCP的三次握手機制,為什么要三次握手? 四次揮手, 為什么要四次揮手,揮手后為什么要保持2MSL? 
    1.1 為什么要有握手?
    1.2 為什么是三次?
    1.3 為什么要四次?
    1.4 為什么包保持2MSL?
2. 簡單介紹下HTTP協議中緩存的處理流程?  
    2.1 緩存的應用流程是什么?
    2.2 與緩存相關的HTTP頭部有哪些?
3. 在地址欄鍵入URL后,網絡世界發生么什么?
4. 使用HTTP長連接有哪些優點?
5. CLOSE_WAIT狀態產生的原因?
6. 介紹下多播是怎樣實現的?
7. 服務器的最大並發連接數是多少?
8. TCP和UDP協議該如何選擇?
9. TLS/SSL協議是如何保障信息安全的?
10. HTTP2協議有哪些優點?
請詳細介紹下TCP的三次握手機制,為什么要三次握手? 四次揮手, 為什么要四次揮手,揮手后為什么要保持2MSL?

三次握手

首先介紹一下三次握手,客戶端發起連接請求(SYN=1,seq=客戶隨機序列),服務端收到請求並回復(SYN=1, seq=服務隨機序列,ACK=1 seq=seq(客戶隨機序列)+1),客戶端收到相應並回復(ACK=1, seq=seq(服務隨機序列)+1),三次握手完成。

為什么是三次不是二次,因為二次握手只能確認客戶端能收到服務端請求,但是服務端不能確認客戶端是否收到請求。同時二次握手無法解決重復連接問題,當握手中網絡擁塞,導致客戶端重新發了一個新的握手請求,過了一會客戶端收到舊握手請求,客戶端就可以向客戶端發送一個RST ,連接中止。一會時間后,新握手抵達,正常建立連接

因為TCP是可靠性連接,通過三次握手可以有效的避免重復連接,確認雙方是否連接,同時節約資源。

四次揮手

客戶端發起斷開連接請求 FIN=1 seq=seq+1,服務端收到請求回復ACK=1 seq=seq+1, 服務端處理完請求后回復FIN=1, seq=seq+1,客戶端收到請求回復ACK=1, seq=seq+1 等待2MSL后連接關閉。

為什么要等待2MSL, 因為1MSL為一次報文在網絡存活的時間,過了這個時間報文會被丟棄(linux中默認2MSL為60秒)。 如果客戶端少於2MSL關閉,網絡擁塞,導致服務端沒有收到請求, 重新發送FIN, 而客戶端已經關閉,這時會導致雙方無法正常關閉。假如此時客戶端新請求使用同個端口連接服務端,而服務端沒有正常關閉,會帶來數據混淆。大於2MSL浪費資源。

1.為了保證連接的可靠關閉。如果server沒有收到最后一個ACK,那么就會重發FIN。

2.為了避免端口重用帶來的數據混淆。如果client直接進入CLOSED狀態,又用相同端口號向server建立一個連接,上一次連接的部分數據在網絡中延遲到達server,數據就可能發生混淆了。

為什么seq要隨機?

​ 這樣是為了網絡安全,如果不是隨機產生初始序列號,黑客將會以很容易的方式獲取到你與其他主機之間的初始化序列號,並且偽造序列號進行攻擊

為什么seq+1?

​ 確認收到的序列,並且告訴發送端下一次發送的序列號從哪里開始(便於接收方對數據排序,便於選擇重傳)

什么是SYN洪范泛攻擊?

  • SYN Flood利用TCP協議缺陷,發送大量偽造的TCP連接請求,常用假冒的IP或IP號段發來海量的請求連接的第一個握手包(SYN包),被攻擊服務器回應第二個握手包(SYN+ACK包),因為對方是假冒IP,對方永遠收不到包且不會回應第三個握手包。導致被攻擊服務器保持大量SYN_RECV狀態的“半連接”,並且會重試默認5次回應第二個握手包,大量隨機的惡意syn占滿了未完成連接隊列,導致正常合法的syn排不上隊列,讓正常的業務請求連接不進來。【服務器端的資源分配是在二次握手時分配的,而客戶端的資源是在完成三次握手時分配的,所以服務器容易受到SYN洪泛攻擊】

檢測 SYN 攻擊非常的方便,當你在服務器上看到大量的半連接狀態時,特別是源IP地址是隨機的,基本上可以斷定這是一次SYN攻擊【在 Linux/Unix 上可以使用系統自帶的 netstats 命令來檢測 SYN 攻擊】

怎么解決?

    • 縮短超時(SYN Timeout)時間
    • 增加最大半連接數
    • 過濾網關防護
    • SYN cookies技術
  1. 當服務器接受到 SYN 報文段時,不直接為該 TCP 分配資源,而只是打開一個半開的套接字。接着會使用 SYN 報文段的源 Id,目的 Id,端口號以及只有服務器自己知道的一個秘密函數生成一個 cookie,並把 cookie 作為序列號響應給客戶端
  2. 如果客戶端是正常建立連接,將會返回一個確認字段為 cookie + 1 的報文段。接下來服務器會根據確認報文的源 Id,目的 Id,端口號以及秘密函數計算出一個結果,如果結果的值 + 1 等於確認字段的值,則證明是剛剛請求連接的客戶端,這時候才為該 TCP 分配

Q:TCP三次握手中,最后一次回復丟失,會發生什么?

  • 如果最后一次ACK在網絡中丟失,那么Server端(服務端)該TCP連接的狀態仍為SYN_RECV,並且根據 TCP的超時重傳機制依次等待3秒、6秒、12秒后重新發送 SYN+ACK 包,以便 Client(客戶端)重新發送ACK包
  • 如果重發指定次數后,仍然未收到ACK應答,那么一段時間后,Server(服務端)自動關閉這個連接
  • 但是Client(客戶端)認為這個連接已經建立,如果Client(客戶端)端向Server(服務端)發送數據,Server端(服務端)將以RST包(Reset,標示復位,用於異常的關閉連接)響應,此時,客戶端知道第三次握手失敗

TCP四次揮手

  1. 主動斷開方(客戶端/服務端)-發送一個 FIN,用來關閉主動斷開方(客戶端/服務端)到被動斷開方(客戶端/服務端)的數據傳送
  2. 被動斷開方(客戶端/服務端)-收到這個 FIN,它發回一 個 ACK,確認序號為收到的序號加1 。和 SYN 一樣,一個 FIN 將占用一個序號
  3. 被動點開方(客戶端/服務端)-關閉與主動斷開方(客戶端/服務端)的連接,發送一個FIN給主動斷開方(客戶端/服務端)
  4. 主動斷開方(客戶端/服務端)-發回 ACK 報文確認,並將確認序號設置為收到序號加1

Q:為什么連接的時候是三次握手,關閉的時候卻是四次握手?

  • 建立連接的時候, 服務器在LISTEN狀態下,收到建立連接請求的SYN報文后,把ACK和SYN放在一個報文里發送給客戶端。
  • 關閉連接時,服務器收到對方的FIN報文時,僅僅表示對方不再發送數據了但是還能接收數據,而自己也未必全部數據都發送給對方了,所以服務器可以立即關閉,也可以發送一些數據給對方后,再發送FIN報文給對方來表示同意現在關閉連接。因此,服務器ACK和FIN一般都會分開發送,從而導致多了一次。

Q:為什么TCP揮手每兩次中間有一個 FIN-WAIT2等待時間?

  • 主動關閉的一端調用完close以后(即發FIN給被動關閉的一端, 並且收到其對FIN的確認ACK)則進入FIN_WAIT_2狀態。如果這個時候因為網絡突然斷掉、被動關閉的一段宕機等原因,導致主動關閉的一端不能收到被動關閉的一端發來的FIN(防止對端不發送關閉連接的FIN包給本端),這個時候就需要FIN_WAIT_2定時器, 如果在該定時器超時的時候,還是沒收到被動關閉一端發來的FIN,那么直接釋放這個鏈接,進入CLOSE狀態

Q:為什么客戶端最后還要等待2MSL?為什么還有個TIME-WAIT的時間等待?

  1. 保證客戶端發送的最后一個ACK報文能夠到達服務器,因為這個ACK報文可能丟失,服務器已經發送了FIN+ACK報文,請求斷開,客戶端卻沒有回應,於是服務器又會重新發送一次,而客戶端就能在這個2MSL時間段內收到這個重傳的報文,接着給出回應報文,並且會重啟2MSL計時器。
  2. 防止類似與“三次握手”中提到了的“已經失效的連接請求報文段”出現在本連接中。客戶端發送完最后一個確認報文后,在這個2MSL時間中,就可以使本連接持續的時間內所產生的所有報文段都從網絡中消失,這樣新的連接中不會出現舊連接的請求報文
  3. 2MSL,最大報文生存時間,一個MSL 30 秒,2MSL = 60s

Q:客戶端 TIME-WAIT 狀態過多會產生什么后果?怎樣處理?

  1. 作為服務器,短時間內關閉了大量的Client連接,就會造成服務器上出現大量的TIME_WAIT連接,占據大量的tuple /tApl/ ,嚴重消耗着服務器的資源,此時部分客戶端就會顯示連接不上
  2. 作為客戶端,短時間內大量的短連接,會大量消耗的Client機器的端口,畢竟端口只有65535個,端口被耗盡了,后續就無法在發起新的連接了
  • 高並發短連接的TCP服務器上,當服務器處理完請求后立刻主動正常關閉連接。這個場景下會出現大量socket處於TIME_WAIT狀態。如果客戶端的並發量持續很高,此時部分客戶端就會顯示連接不上

    • 高並發可以讓服務器在短時間范圍內同時占用大量端口,而端口有個0~65535的范圍,並不是很多,刨除系統和其他服務要用的,剩下的就更少了
    • 短連接表示“業務處理+傳輸數據的時間 遠遠小於 TIMEWAIT超時的時間”的連接
  • 解決方法:

    • 用負載均衡來抗這些高並發的短請求;
    • 服務器可以設置 SO_REUSEADDR 套接字選項來避免 TIME_WAIT狀態,TIME_WAIT 狀態可以通過優化服務器參數得到解決,因為發生TIME_WAIT的情況是服務器自己可控的,要么就是對方連接的異常,要么就是自己沒有迅速回收資源,總之不是由於自己程序錯誤導致的
    • 強制關閉,發送 RST 包越過TIMEWAIT狀態,直接進入CLOSED狀態

Q:服務器出現了大量 CLOSE_WAIT 狀態如何解決?

  • 大量 CLOSE_WAIT 表示程序出現了問題,對方的 socket 已經關閉連接,而我方忙於讀或寫沒有及時關閉連接,需要檢查代碼,特別是釋放資源的代碼,或者是處理請求的線程配置。

Q:服務端會有一個TIME_WAIT狀態嗎?如果是服務端主動斷開連接呢?

  • 發起鏈接的主動方基本都是客戶端,但是斷開連接的主動方服務器和客戶端都可以充當,也就是說,只要是主動斷開連接的,就會有 TIME_WAIT狀態

  • 四次揮手是指斷開一個TCP連接時,需要客戶端和服務端總共發送4個包以確認連接的斷開。在socket編程中,這一過程由客戶端或服務端任一方執行close來觸發

  • 由於TCP連接時全雙工的,因此,每個方向的數據傳輸通道都必須要單獨進行關閉。

簡單介紹下HTTP協議中緩存的處理流程?

Expires、Cache-control、緩存時間、Etag、Last-Modified

Expires:
	版本:HTTP1.0
	作用:指定緩存的到期時間,時間為從服務器返回的絕對時間

	缺點:返回的緩存時間是服務器的絕對時間,跟本地的時間有誤差,更改本地時間會對緩存的處理產生影響

Cache-Control:
	版本:HTTP1.1
	作用:用來取代Expires,有多個屬性,可以很好的控制瀏覽器緩存
	no-cache:不啟用緩存
	max-age:用戶請求時,會生成一個緩存的副本,副本過期的期限由關鍵字的相對時間來決定
	only-if-cached:告知服務器,僅能返回緩存的響應,沒有緩存就返回504
	max-state:請求不到數據、展現緩存上的數據,max-state就是定義一個可以超出期限時間使用緩存的時間段。
	public:所有都緩存
	private:對單個用戶或部分響應信息,不能被共享緩存處理

Last-Modified:
	作用:服務器將資源傳遞給客戶端時,會將資源最后更改的時間以"Last-Modified:GMT"的形式加在實體首部上一起返回給客戶端,下次請求是,會把改信息附帶在請求報文中一並帶給服務器去做檢查,如果值和服務器上最終修改時間一致,則說明該資源沒有被更改,直接返回304狀態碼

ETag:
	作用:web服務器響應請求時,告訴瀏覽器當前資源在服務器的唯一標識(生成規則有服務器決定)。

在地址欄鍵入URL后,網絡世界發生么什么?

​ 先域名解析 在瀏覽器上查詢對應DNS緩存,沒有到本機,沒有到hosts文件, 沒有到路由,沒有再到網絡服務商, 沒有根DNS服務器 返回ip, 通過ip請求建立連接TCP(HTTPS/HTTP) 三次握手 到服務器獲取數據 返回四次揮手 瀏覽器渲染

使用HTTP長連接有哪些優點?

http1.0默認是短連接。也就是說,客戶端和服務器每進行一次HTTP操作就會建立一次連接,任務結束就會中斷連接。導致一個頁面可能要請求很多次連接。浪費資源

http1.1支持長連接 在相應頭加入connection:keep-alive ,建立連接之后其他請求也可能通過這個連接。 可以省去較多的新建TCP和關閉的操作,省時。比較適合請求資源頻繁的客戶。一般客戶端不會主動關閉連接,如果連接一直不關閉的話,會存在一個問題,隨着用戶端連接越來越多,server會扛不住。這時候服務端需要一些額外策略來關閉這些連接。限制每個客戶端的最大連接數

5. CLOSE_WAIT狀態產生的原因?

如果我們的服務器程序處於CLOSE_WAIT狀態的話,說明套接字是被動關閉的!

6. 介紹下多播是怎樣實現的?

解答思路:先解釋什么是多播,介紹使用多播有什么好處

TCP單播

​ 單播,轉發一百次 都是用一個主機進行的復制100次

UDP 廣播、多播

​ 但是,多播一般是由網絡設備交換機和路由器來做這個事情,可以提升發送端的性能

7. 服務器的最大並發連接數是多少?

解答思路:先解釋並發連接是受什么來決定的?在回答具體的最大並發連接數,以及如何擴大該連接數(延伸方面可以再回答怎么實現高並發以及LInux下的高並發優化)

首先,問題中描述的65535(2的16次方)個連接指的是客戶端連接數的限制,而你作為服務器,別人來連你,理論上是沒有限制的。注意,僅僅理論上。

65535是怎么來的?

是TCP協議規定的端口字段的最大范圍,2個字節,16比特,每一比特有0和1 2種狀態,按照排列組合,2的16次方,一共就是65536,端口0預留不用,就是65535。

8. TCP和UDP協議該如何選擇?

解答思路:兩者對比分別分析其優點,再根據實際情況進行選擇。

TCP 與 UDP 的區別:TCP是面向連接的,可靠的字節流服務;

UDP是面向無連接的,不可靠的數據報服務。

UDP:一對多、高效、簡單、實時性好、無隊頭阻塞問題

TCP:傳遞任意長度消息、可靠、流量控制、擁塞控制

常見的 TCP應用有:FTP、SSH、Telnet、SMTP、HTTP;

常見的UDP應用有:流媒體、實時游戲、直播、物聯網、QQ 文件傳輸、QQ語音、QQ視頻等

9. TLS/SSL協議是如何保障信息安全的?

解答思路:解釋PKI證書體系、密鑰交換協議、對稱加密算法

加密分為“對稱加密”和“非對稱加密”兩種:

對稱加密:所謂的“對稱加密”,意思就是說:“加密”和“解密”使用相同的密鑰。

非對稱加密::所謂的“非對稱加密”,意思就是說:“加密”和“解密”使用不同的密鑰。

10. HTTP2協議有哪些優點?

首先HTTP2是在HTTP1.x版本上的改良。

1、多路復用。HTTP1.x版本長連接不支持多路復用,是一次請求-響應,建立一個連接,用完關閉,每一個請求都要建立一個連接,在2.0可以多個請求可同時在一個連接上並行執行;

2、二進制分幀。1.x解析基於文本,在2.0中基於二進制,解析錯誤少,更高效;

3、服務端推送。此外在2.0之后支持服務端推送(一種在客戶端請求之前發送數據的機制,服務器可以對客戶端的一個請求發送多個響應。服務端推送讓 HTTP1.x 時代使用內嵌資源的優化手段變得沒有意義);

4、首部壓縮。HTTP/1.1並不支持 HTTP 首部壓縮,在 HTTP/2 使用了專門為首部壓縮而設計的 HPACK 算法。

5、Stream優先級。在HTTP2.0中Stream可以根據依賴關系和權重設置優先級。先級高的stream會被server優先處理和返回給客戶端,stream還可以依賴其它的sub streams。

11. TCP報文首部有哪些字段,說說其作用

image

  • 16位端口號:源端口號,主機該報文段是來自哪里;目標端口號,要傳給哪個上層協議或應用程序
  • 32位序號:一次TCP通信(從TCP連接建立到斷開)過程中某一個傳輸方向上的字節流的每個字節的編號。
  • 32位確認號:用作對另一方發送的tcp報文段的響應。其值是收到的TCP報文段的序號值加1。
  • 4位頭部長度:表示tcp頭部有多少個32bit字(4字節)。因為4位最大能標識15,所以TCP頭部最長是60字節。
  • 6位標志位:URG(緊急指針是否有效),ACK(表示確認號是否有效),PSH(緩沖區尚未填滿),RST(表示要求對方重新建立連接),SYN(建立連接消息標志接),FIN(表示告知對方本端要關閉連接了)
  • 16位窗口大小:是TCP流量控制的一個手段。這里說的窗口,指的是接收通告窗口。它告訴對方本端的TCP接收緩沖區還能容納多少字節的數據,這樣對方就可以控制發送數據的速度。
  • 16位校驗和:由發送端填充,接收端對TCP報文段執行CRC算法以檢驗TCP報文段在傳輸過程中是否損壞。注意,這個校驗不僅包括TCP頭部,也包括數據部分。這也是TCP可靠傳輸的一個重要保障。
  • 16位緊急指針:一個正的偏移量。它和序號字段的值相加表示最后一個緊急數據的下一字節的序號。因此,確切地說,這個字段是緊急指針相對當前序號的偏移,不妨稱之為緊急偏移。TCP的緊急指針是發送端向接收端發送緊急數據的方法

12. TCP是如何保證可靠性的

  • TCP的連接是基於三次握手,而斷開則是四次揮手。確保連接和斷開的可靠性。
  • TCP的可靠性,還體現在有狀態;TCP會記錄哪些數據發送了,哪些數據被接受了,哪些沒有被接受,並且保證數據包按序到達,保證數據傳輸不出差錯。
  • TCP的可靠性,還體現在可控制。它有報文校驗、ACK應答、超時重傳(發送方)、失序數據重傳(接收方)、丟棄重復數據、流量控制(滑動窗口)和擁塞控制等機制。

13 . TCP重傳機制

超時重傳

TCP 為了實現可靠傳輸,實現了重傳機制。最基本的重傳機制,就是超時重傳,即在發送數據報文時,設定一個定時器,每間隔一段時間,沒有收到對方的ACK確認應答報文,就會重發該報文。

這個間隔時間,一般設置為多少呢?我們先來看下什么叫RTT(Round-Trip Time,往返時間)

image

RTT就是,一個數據包從發出去到回來的時間,即數據包的一次往返時間。超時重傳時間,就是Retransmission Timeout ,簡稱RTO

RTO設置多久呢?

  • 如果RTO比較小,那很可能數據都沒有丟失,就重發了,這會導致網絡阻塞,會導致更多的超時出現。
  • 如果RTO比較大,等到花兒都謝了還是沒有重發,那效果就不好了。

一般情況下,RTO略大於RTT,效果是最好的。一些小伙伴會問,超時時間有沒有計算公式呢?有的!有個標准方法算RTO的公式,也叫Jacobson / Karels 算法。我們一起來看下計算RTO的公式

1. 先計算SRTT(計算平滑的RTT)

SRTT = (1 - α) * SRTT + α * RTT  //求 SRTT 的加權平均

2. 再計算RTTVAR (round-trip time variation)

RTTVAR = (1 - β) * RTTVAR + β * (|RTT - SRTT|) //計算 SRTT 與真實值的差距

3. 最終的RTO

RTO = µ * SRTT + ∂ * RTTVAR  =  SRTT + 4·RTTVAR  

其中,α = 0.125,β = 0.25, μ = 1,∂ = 4,這些參數都是大量結果得出的最優參數。

但是,超時重傳會有這些缺點:

  • 當一個報文段丟失時,會等待一定的超時周期然后才重傳分組,增加了端到端的時延。
  • 當一個報文段丟失時,在其等待超時的過程中,可能會出現這種情況:其后的報文段已經被接收端接收但卻遲遲得不到確認,發送端會認為也丟失了,從而引起不必要的重傳,既浪費資源也浪費時間。

並且,TCP有個策略,就是超時時間間隔會加倍。超時重傳需要等待很長時間。因此,還可以使用快速重傳機制。

快速重傳

快速重傳機制,它不以時間驅動,而是以數據驅動。它基於接收端的反饋信息來引發重傳。

一起來看下快速重傳流程:

image快速重傳流程

發送端發送了 1,2,3,4,5,6 份數據:

  • 第一份 Seq=1 先送到了,於是就 Ack 回 2;
  • 第二份 Seq=2 也送到了,假設也正常,於是ACK 回 3;
  • 第三份 Seq=3 由於網絡等其他原因,沒送到;
  • 第四份 Seq=4 也送到了,但是因為Seq3沒收到。所以ACK回3;
  • 后面的 Seq=4,5的也送到了,但是ACK還是回復3,因為Seq=3沒收到。
  • 發送端連着收到三個重復冗余ACK=3的確認(實際上是4個,但是前面一個是正常的ACK,后面三個才是重復冗余的),便知道哪個報文段在傳輸過程中丟失了,於是在定時器過期之前,重傳該報文段。
  • 最后,接收到收到了 Seq3,此時因為 Seq=4,5,6都收到了,於是ACK回7.

快速重傳還可能會有個問題:ACK只向發送端告知最大的有序報文段,到底是哪個報文丟失了呢?並不確定!那到底該重傳多少個包呢?

是重傳 Seq3 呢?還是重傳 Seq3、Seq4、Seq5、Seq6 呢?因為發送端並不清楚這三個連續的 ACK3 是誰傳回來的。

帶選擇確認的重傳(SACK)

為了解決快速重傳的問題:應該重傳多少個包? TCP提供了SACK方法(帶選擇確認的重傳,Selective Acknowledgment)。

SACK機制就是,在快速重傳的基礎上,接收端返回最近收到的報文段的序列號范圍,這樣發送端就知道接收端哪些數據包沒收到,醬紫就很清楚該重傳哪些數據包啦。SACK標記是加在TCP頭部選項字段里面的。

imageSACK機制

如上圖中,發送端收到了三次同樣的ACK=30的確認報文,於是就會觸發快速重發機制,通過SACK信息發現只有30~39這段數據丟失,於是重發時就只選擇了這個30~39的TCP報文段進行重發。

D-SACK

D-SACK,即Duplicate SACK(重復SACK),在SACK的基礎上做了一些擴展,,主要用來告訴發送方,有哪些數據包自己重復接受了。DSACK的目的是幫助發送方判斷,是否發生了包失序、ACK丟失、包重復或偽重傳。讓TCP可以更好的做網絡流控。來看個圖吧:

image

14. TCP滑動窗口

TCP 發送一個數據,需要收到確認應答,才會發送下一個數據。這樣有個缺點,就是效率會比較低。

這就好像我們面對面聊天,你說完一句,我應答后,你才會說下一句。那么,如果我在忙其他事情,沒有能夠及時回復你。你說完一句后,要等到我忙完回復你,你才說下句,這顯然很不現實。

為了解決這個問題,TCP引入了窗口,它是操作系統開辟的一個緩存空間。窗口大小值表示無需等待確認應答,而可以繼續發送數據的最大值。

TCP頭部有個字段叫win,也即那個16位的窗口大小,它告訴對方本端的TCP接收緩沖區還能容納多少字節的數據,這樣對方就可以控制發送數據的速度,從而達到流量控制的目的。

通俗點講,就是接受方每次收到數據包,在發送確認報文的時候,同時告訴發送方,自己的緩存區還有多少空余空間,緩沖區的空余空間,我們就稱之為接受窗口大小。這就是win。

TCP 滑動窗口分為兩種: 發送窗口和接收窗口。發送端的滑動窗口包含四大部分,如下:

  • 已發送且已收到ACK確認
  • 已發送但未收到ACK確認
  • 未發送但可以發送
  • 未發送也不可以發送

image

  • 虛線矩形框,就是發送窗口。
  • SND.WND: 表示發送窗口的大小,上圖虛線框的格子數就是14個。
  • SND.UNA: 一個絕對指針,它指向的是已發送但未確認的第一個字節的序列號。
  • SND.NXT:下一個發送的位置,它指向未發送但可以發送的第一個字節的序列號。

接收方的滑動窗口包含三大部分,如下:

  • 已成功接收並確認
  • 未收到數據但可以接收
  • 未收到數據並不可以接收的數據

image

  • 虛線矩形框,就是接收窗口。
  • REV.WND: 表示接收窗口的大小,上圖虛線框的格子就是9個。
  • REV.NXT:下一個接收的位置,它指向未收到但可以接收的第一個字節的序列號。

15. TCP流量控制

TCP 提供一種機制可以讓發送端根據接收端的實際接收能力控制發送的數據量,這就是流量控制

首先雙方三次握手,初始化各自的窗口大小,均為 400 個字節。

imageTCP的流量控制圖

16.TCP擁塞控制

擁塞控制是作用於網絡的,防止過多的數據包注入到網絡中,避免出現網絡負載過大的情況。它的目標主要是最大化利用網絡上瓶頸鏈路的帶寬。它跟流量控制又有什么區別呢?流量控制是作用於接收者的,根據接收端的實際接收能力控制發送速度,防止分組丟失的。

只要網絡中沒有出現擁塞,擁塞窗口的值就可以再增大一些,以便把更多的數據包發送出去,但只要網絡出現擁塞,擁塞窗口的值就應該減小一些,以減少注入到網絡中的數據包數。

實際上,擁塞控制主要有這幾種常用算法

  • 慢啟動
  • 擁塞避免
  • 擁塞發生
  • 快速恢復

慢啟動算法

慢啟動算法,表面意思就是,別急慢慢來。它表示TCP建立連接完成后,一開始不要發送大量的數據,而是先探測一下網絡的擁塞程度。由小到大逐漸增加擁塞窗口的大小,如果沒有出現丟包,每收到一個ACK,就將擁塞窗口cwnd大小就加1(單位是MSS)每輪次發送窗口增加一倍,呈指數增長,如果出現丟包,擁塞窗口就減半,進入擁塞避免階段。

  • TCP連接完成,初始化cwnd = 1,表明可以傳一個MSS單位大小的數據。
  • 每當收到一個ACK,cwnd就加一;
  • 每當過了一個RTT,cwnd就增加一倍; 呈指數讓升

image

為了防止cwnd增長過大引起網絡擁塞,還需設置一個慢啟動閥值ssthresh(slow start threshold)狀態變量。當cwnd到達該閥值后,就好像水管被關小了水龍頭一樣,減少擁塞狀態。即當cwnd >ssthresh時,進入了擁塞避免算法。

擁塞避免算法

一般來說,慢啟動閥值ssthresh是65535字節,cwnd到達慢啟動閥值

  • 每收到一個ACK時,cwnd = cwnd + 1/cwnd
  • 當每過一個RTT時,cwnd = cwnd + 1

顯然這是一個線性上升的算法,避免過快導致網絡擁塞問題。

image

擁塞發生

當網絡擁塞發生丟包時,會有兩種情況:

  • RTO超時重傳
  • 快速重傳

如果是發生了RTO超時重傳,就會使用擁塞發生算法

  • 慢啟動閥值sshthresh = cwnd /2
  • cwnd 重置為 1
  • 進入新的慢啟動過程

image

這真的是辛辛苦苦幾十年,一朝回到解放前。其實還有更好的處理方式,就是快速重傳。發送方收到3個連續重復的ACK時,就會快速地重傳,不必等待RTO超時再重傳。

imageimage.png

慢啟動閥值ssthresh 和 cwnd 變化如下:

  • 擁塞窗口大小 cwnd = cwnd/2
  • 慢啟動閥值 ssthresh = cwnd
  • 進入快速恢復算法

快速恢復

快速重傳和快速恢復算法一般同時使用。快速恢復算法認為,還有3個重復ACK收到,說明網絡也沒那么糟糕,所以沒有必要像RTO超時那么強烈。

正如前面所說,進入快速恢復之前,cwnd 和 sshthresh已被更新:

- cwnd = cwnd /2
- sshthresh = cwnd

然后,真正的快速算法如下:

  • cwnd = sshthresh + 3
  • 重傳重復的那幾個ACK(即丟失的那幾個數據包)
  • 如果再收到重復的 ACK,那么 cwnd = cwnd +1
  • 如果收到新數據的 ACK 后, cwnd = sshthresh。因為收到新數據的 ACK,表明恢復過程已經結束,可以再次進入了擁塞避免的算法了。

image

17. 半連接隊列和 SYN Flood 攻擊的關系

TCP進入三次握手前,服務端會從CLOSED狀態變為LISTEN狀態,同時在內部創建了兩個隊列:半連接隊列(SYN隊列)和全連接隊列(ACCEPT隊列)。

什么是半連接隊列(SYN隊列) 呢? 什么是全連接隊列(ACCEPT隊列) 呢?回憶下TCP三次握手的圖:

image三次握手

  • TCP三次握手時,客戶端發送SYN到服務端,服務端收到之后,便回復ACK和SYN,狀態由LISTEN變為SYN_RCVD,此時這個連接就被推入了SYN隊列,即半連接隊列。
  • 當客戶端回復ACK, 服務端接收后,三次握手就完成了。這時連接會等待被具體的應用取走,在被取走之前,它被推入ACCEPT隊列,即全連接隊列。

SYN Flood是一種典型的DoS (Denial of Service,拒絕服務) 攻擊,它在短時間內,偽造不存在的IP地址,向服務器大量發起SYN報文。當服務器回復SYN+ACK報文后,不會收到ACK回應報文,導致服務器上建立大量的半連接半連接隊列滿了,這就無法處理正常的TCP請求啦。

主要有 syn cookieSYN Proxy防火牆等方案應對。

  • syn cookie:在收到SYN包后,服務器根據一定的方法,以數據包的源地址、端口等信息為參數計算出一個cookie值作為自己的SYNACK包的序列號,回復SYN+ACK后,服務器並不立即分配資源進行處理,等收到發送方的ACK包后,重新根據數據包的源地址、端口計算該包中的確認序列號是否正確,如果正確則建立連接,否則丟棄該包。
  • SYN Proxy防火牆:服務器防火牆會對收到的每一個SYN報文進行代理和回應,並保持半連接。等發送方將ACK包返回后,再重新構造SYN包發到服務器,建立真正的TCP連接。

18 Nagle算法和延遲確認

Nagle算法

如果發送端瘋狂地向接收端發送很小的包,比如就1個字節,那么親愛的小伙伴,你們覺得會有什么問題呢?

TCP/IP協議中,無論發送多少數據,總是要在數據前面加上協議頭,同時,對方接收到數據,也需要發送ACK表示確認。為了盡可能的利用網絡帶寬,TCP總是希望盡可能的發送足夠大的數據。Nagle算法就是為了盡可能發送大塊數據,避免網絡中充斥着許多小數據塊。

Nagle算法的基本定義是:任意時刻,最多只能有一個未被確認的小段。所謂“小段”,指的是小於MSS尺寸的數據塊,所謂“未被確認”,是指一個數據塊發送出去后,沒有收到對方發送的ACK確認該數據已收到。

Nagle算法的實現規則:

  • 如果包長度達到MSS,則允許發送;
  • 如果該包含有FIN,則允許發送;
  • 設置了TCP_NODELAY選項,則允許發送;
  • 未設置TCP_CORK選項時,若所有發出去的小數據包(包長度小於MSS)均被確認,則允許發送;
  • 上述條件都未滿足,但發生了超時(一般為200ms),則立即發送。

延遲確認

如果接受方剛接收到發送方的數據包,在很短很短的時間內,又接收到第二個包。那么請問接收方是一個一個地回復好點,還是合並一起回復好呢?

接收方收到數據包后,如果暫時沒有數據要發給對端,它可以等一段時再確認(Linux上默認是40ms)。如果這段時間剛好有數據要傳給對端,ACK就隨着數據傳輸,而不需要單獨發送一次ACK。如果超過時間還沒有數據要發送,也發送ACK,避免對端以為丟包。

但是有些場景不能延遲確認,比如發現了亂序包接收到了大於一個 frame 的報文,且需要調整窗口大小等。

一般情況下,Nagle算法和延遲確認不能一起使用,Nagle算法意味着延遲發,延遲確認意味着延遲接收,醬紫就會造成更大的延遲,會產生性能問題。

19. TCP粘包和拆包

TCP是面向流,沒有界限的一串數據。TCP底層並不了解上層業務數據的具體含義,它會根據TCP緩沖區的實際情況進行包的划分,所以在業務上認為,一個完整的包可能會被TCP拆分成多個包進行發送也有可能把多個小的包封裝成一個大的數據包發送,這就是所謂的TCP粘包和拆包問題。

imageTCP的粘包和拆包

為什么會產生粘包和拆包呢?

  • 要發送的數據小於TCP發送緩沖區的大小,TCP將多次寫入緩沖區的數據一次發送出去,將會發生粘包;
  • 接收數據端的應用層沒有及時讀取接收緩沖區中的數據,將發生粘包;
  • 要發送的數據大於TCP發送緩沖區剩余空間大小,將會發生拆包;
  • 待發送數據大於MSS(最大報文長度),TCP在傳輸前將進行拆包。即TCP報文長度-TCP頭部長度>MSS。

解決方案:

  • 發送端將每個數據包封裝為固定長度
  • 在數據尾部增加特殊字符進行分割
  • 將數據分為兩部分,一部分是頭部,一部分是內容體;其中頭部結構大小固定,且有一個字段聲明內容體的大小。

select和epoll的區別?

select

1)每次調用select,都需要把fd集合(文件描述集合)從用戶態拷貝到內核態,這個開銷在fd很多時會很大

2)同時每次調用select都需要在內核遍歷傳遞進來的所有fd,這個開銷在fd很多時也很大

epoll

epoll通過在Linux內核中申請一個簡易的文件系統(文件系統一般用什么數據結構實現?紅黑樹)。把原先的select/poll調用分成了3個部分:

1)調用epoll_create( ), 創建紅黑樹和就緒鏈表。

2)調用epoll_ctl() ,如果增加請求socket, 先檢查紅黑樹中是否存在,存在直接返回,不存在則添加到紅黑樹上,然后向內核注冊回調函數,用於當中斷事件來臨時向就緒鏈表中插入socket。

3)調用epoll_wait(), 調用epoll_wait時,返回就緒鏈表的數據。

epoll觸發方式水平觸發LT邊緣觸發ET

EPOLLIN事件(可讀)

內核中的socket接收緩沖區為空 低電平

內核中的socket接收緩沖區不為空 高電平

EPOLLOUT事件(可寫)

內核中的socke發送緩沖區不滿 高電平

內核中的socke發送緩沖區滿 低電平

LT是水平觸發,也就是高電平就會觸發

ET是邊沿觸發,低電平->高電平或者高電平->低電平觸發

水平觸發

LT模式下,只要一個句柄上的事件 沒有處理完,重新將這個句柄放到就緒鏈表中,調用epoll_wait時會返回這個句柄

邊緣觸發

ET模式下,只要一個句柄上的事件 沒有處理完,僅在第一次返回 。除非新中斷到。

1.對於讀操作,如果read沒有一次讀完buff數據,下一次將得不到就緒通知(ET特性),造成buff中數據無法讀出,除非有新數據到達。

解決方法:將套接字設置為非阻塞,用while循環包住read,只要buff中有數據,就一直讀。一直讀到產生EAGIN錯誤。若ET模式下使用阻塞IO,則程序一定會阻塞在最后一次write或read操作,因此說ET模式下一定要使用非阻塞IO。

2.對於寫操作主要因為ET模式下非阻塞需要我們考慮如何將用戶要求寫的數據寫完。

解決方法:只要buff還有空間且用戶請求寫的數據還未寫完,就一直寫。

所以說LT同時支持阻塞I/O和非阻塞I/O,而ET模式只能支持非阻塞I/O。

區別

1、支持一個進程所能打開的最大連接數

select:單個進程所能打開的最大連接數有FD_SETSIZE宏定義,其大小是32個整數的大小(在32位的機器上,大小就是3232,同理64位機器上FD_SETSIZE為3264),當然我們可以對進行修改,然后重新編譯內核,但是性能可能會受到影響,這需要進一步的測試。

poll:poll本質上和select沒有區別,但是它沒有最大連接數的限制,原因是它是基於鏈表來存儲的。

epoll:雖然連接數有上限,但是很大,1G內存的機器上可以打開10萬左右的連接,2G內存的機器可以打開20萬左右的連接。

2、FD劇增后帶來的IO效率問題

select:因為每次調用時都會對連接進行線性遍歷,所以隨着FD的增加會造成遍歷速度慢的“線性下降性能問題”。

poll:同上

epoll:因為epoll內核中實現是根據每個fd上的callback函數來實現的,只有活躍的socket才會主動調用callback,所以在活躍socket較少的情況下,使用epoll沒有前面兩者的線性下降的性能問題,但是所有socket都很活躍的情況下,可能會有性能問題。

3、 消息傳遞方式

select:內核需要將消息傳遞到用戶空間,都需要內核拷貝動作

poll:同上

epoll:epoll通過內核和用戶空間共享一塊內存來實現的。

http與https的區別,加密怎么加?

HTTPS(Secure Hypertext Transfer Protocol)安全超文本傳輸協議

它是一個安全通信通道,它基於HTTP開發,用於在客戶計算機和服務器之間交換信息。它使用安全套接字層(SSL)進行信息交換,簡單來說它是HTTP的安全版。

http與https的區別在於

http一般使用的是80端口,而https使用的是443端口

https協議需要ca證書

http是明文傳輸的,而https是通過ssl加密之后傳輸的。

https使用的是非對稱加密,所謂的非對稱加密就是加密密鑰與解密密鑰是不相同的。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM