一文帶你吃透計算機網路(上)

qi66發表於2023-03-11


文章字數大約2.1萬字,閱讀大概需要70分鐘,建議收藏後慢慢閱讀!!!

1. TCP/IP協議

  1. TCP/IP網路模型有哪幾層,分別有什麼作用

    應用層

    最上層的,也是我們能直接接觸到的就是應用層Application Layer),我們電腦或手機使用的應用軟體都是在應用層實現。

    所以,應用層只需要專注於為使用者提供應用功能,比如 HTTP、FTP、Telnet、DNS、SMTP等。

    應用層是不用去關心資料是如何傳輸的,而且應用層是工作在作業系統中的使用者態,傳輸層及以下則工作在核心態。

    傳輸層

    應用層的資料包會傳給傳輸層,傳輸層Transport Layer)是為應用層提供網路支援的。

    在傳輸層會有兩個傳輸協議,分別是 TCP 和 UDP。

    TCP 的全稱叫傳輸控制協議(Transmission Control Protocol),大部分應用使用的正是 TCP 傳輸層協議,比如 HTTP 應用層協議。TCP 相比 UDP 多了很多特性,比如流量控制、超時重傳、擁塞控制等,這些都是為了保證資料包能可靠地傳輸給對方。

    UDP 相對來說就很簡單,簡單到只負責傳送資料包,不保證資料包是否能抵達對方,但它實時性相對更好,傳輸效率也高。當然,UDP 也可以實現可靠傳輸,把 TCP 的特性在應用層上實現就可以,不過要實現一個商用的可靠 UDP 傳輸協議,也不是一件簡單的事情。

    應用需要傳輸的資料可能會非常大,如果直接傳輸就不好控制,因此當傳輸層的資料包大小超過 MSS(TCP 最大報文段長度) ,就要將資料包分塊,這樣即使中途有一個分塊丟失或損壞了,只需要重新傳送這一個分塊,而不用重新傳送整個資料包。在 TCP 協議中,我們把每個分塊稱為一個 TCP 段TCP Segment)。

    網路層

    我們不希望傳輸層協議處理太多的事情,只需要服務好應用即可,讓其作為應用間資料傳輸的媒介,幫助實現應用到應用的通訊,而實際的傳輸功能就交給下一層,也就是網路層Internet Layer)。

    網路層最常使用的是 IP 協議(Internet Protocol),IP 協議會將傳輸層的報文作為資料部分,再加上 IP 包頭組裝成 IP 報文,如果 IP 報文大小超過 MTU(乙太網中一般為 1500 位元組)就會再次進行分片,得到一個即將傳送到網路的 IP 報文。

    IP 協議的定址作用是告訴我們去往下一個目的地該朝哪個方向走,路由則是根據「下一個目的地」選擇路徑。定址更像在導航,路由更像在操作方向盤。

    網路介面層

    生成了 IP 頭部之後,接下來要交給網路介面層Link Layer)在 IP 頭部的前面加上 MAC 頭部,並封裝成資料幀(Data frame)傳送到網路上。

    乙太網在判斷網路包目的地時和 IP 的方式不同,因此必須採用相匹配的方式才能在乙太網中將包發往目的地,而 MAC 頭部就是幹這個用的,所以,在乙太網進行通訊要用到 MAC 地址。

    MAC 頭部是乙太網使用的頭部,它包含了接收方和傳送方的 MAC 地址等資訊,我們可以透過 ARP 協議獲取對方的 MAC 地址。

    所以說,網路介面層主要為網路層提供「鏈路級別」傳輸的服務,負責在乙太網、WiFi 這樣的底層網路上傳送原始資料包,工作在網路卡這個層次,使用 MAC 地址來標識網路上的裝置。

  2. 輸入網址到網頁顯示,期間發生了什麼

    • 根據域名,進行DNS域名解析;
    • 拿到解析的IP地址,建立TCP連線;
    • 向IP地址,傳送HTTP請求;
    • 伺服器處理請求;
    • 返回響應結果;
    • 關閉TCP連線;
    • 瀏覽器解析HTML;
    • 瀏覽器佈局渲染;

    背後有哪些技術

    1、查瀏覽器快取,看看有沒有已經快取好的,如果沒有

    2 、檢查本機host檔案,

    3、呼叫API,Linux下Socket函式 gethostbyname

    4、向DNS伺服器傳送DNS請求,查詢本地DNS伺服器,這其中用的是UDP的協議

    5、如果在一個子網內採用ARP地址解析協議進行ARP查詢如果不在一個子網那就需要對預設閘道器進行DNS查詢,如果還找不到會一直向上找根DNS伺服器,直到最終拿到IP地址(全球400多個根DNS伺服器,由13個不同的組織管理)

    6、這個時候我們就有了伺服器的IP地址 以及預設的埠號了,http預設是80 https是 443 埠號,會,首先嚐試http然後呼叫Socket建立TCP連線,

    7、經過三次握手成功建立連線後,開始傳送資料,如果正是http協議的話,就返回就完事了,

    8、如果不是http協議,伺服器會返回一個5開頭的的重定向訊息,告訴我們用的是https,那就是說IP沒變,但是埠號從80變成443了,好了,再四次揮手,完事,

    9、再來一遍,這次除了上述的埠號從80變成443之外,還會採用SSL的加密技術來保證傳輸資料的安全性,保證資料傳輸過程中不被修改或者替換之類的,

    10、這次依然是三次握手,溝通好雙方使用的認證演演算法,加密和檢驗演演算法,在此過程中也會檢驗對方的CA安全證書。

    11、確認無誤後,開始通訊,然後伺服器就會返回你所要訪問的網址的一些資料,在此過程中會將介面進行渲染,牽涉到ajax技術之類的,直到最後我們看到色彩斑斕的網頁

2. HTTP/HTTPS協議

  1. 什麼是HTTP協議

    HTTP 是超文字傳輸協議,也就是HyperText Transfer Protocol。

    HTTP 的名字「超文字協議傳輸」,它可以拆成三個部分:

    • 超文字
    • 傳輸
    • 協議
  2. GET和POST

    GET 用於獲取資源,而 POST 用於傳輸實體主體。

    1. get是獲取資料,post是修改資料

    2. get把請求的資料放在url上, 以?分割URL和傳輸資料,引數之間以&相連,所以get不太安全。而post把資料放在HTTP的包體內(request body 相對安全)

    3. get提交的資料最大是2k( 限制實際上取決於瀏覽器), post理論上沒有限制。

    4. GET產生一個TCP資料包,瀏覽器會把http header和data一併傳送出去,伺服器響應200(返回資料); POST產生兩個TCP資料包,瀏覽器先傳送header,伺服器響應100 continue,瀏覽器再傳送data,伺服器響應200 ok(返回資料)。

    5. GET請求會被瀏覽器主動快取,而POST不會,除非手動設定。

    6. 本質區別:GET是冪等的,而POST不是冪等的

      這裡的冪等性:冪等性是指一次和多次請求某一個資源應該具有同樣的副作用。簡單來說意味著對同一URL的多個請求應該返回同樣的結果。

    正因為它們有這樣的區別,所以不應該且不能用get請求做資料的增刪改這些有副作用的操作。因為get請求是冪等的,在網路不好的隧道中會嘗試重試。如果用get請求增資料,會有重複操作的風險,而這種重複操作可能會導致副作用(瀏覽器和作業系統並不知道你會用get請求去做增操作)。

  3. HTTP快取技術

    對於一些具有重複性的 HTTP 請求,比如每次請求得到的資料都一樣的,我們可以把這對「請求-響應」的資料都快取在本地,那麼下次就直接讀取本地的資料,不必在透過網路獲取伺服器的響應了,這樣的話 HTTP/1.1 的效能肯定肉眼可見的提升。

    所以,避免傳送 HTTP 請求的方法就是透過快取技術,HTTP 快取有兩種實現方式,分別是強制快取和協商快取

    強制快取

    強快取指的是隻要瀏覽器判斷快取沒有過期,則直接使用瀏覽器的本地快取,決定是否使用快取的主動性在於瀏覽器這邊。

    強快取是利用下面這兩個 HTTP 響應頭部(Response Header)欄位實現的,它們都用來表示資源在客戶端快取的有效期:

    • Cache-Control, 是一個相對時間;
    • Expires,是一個絕對時間;

    如果 HTTP 響應頭部同時有 Cache-Control 和 Expires 欄位的話,Cache-Control 的優先順序高於 Expires

    Cache-control 選項更多一些,設定更加精細,所以建議使用 Cache-Control 來實現強快取。具體的實現流程如下:

    • 當瀏覽器第一次請求訪問伺服器資源時,伺服器會在返回這個資源的同時,在 Response 頭部加上 Cache-Control,Cache-Control 中設定了過期時間大小;
    • 瀏覽器再次請求訪問伺服器中的該資源時,會先透過請求資源的時間與 Cache-Control 中設定的過期時間大小,來計算出該資源是否過期,如果沒有,則使用該快取,否則重新請求伺服器;
    • 伺服器再次收到請求後,會再次更新 Response 頭部的 Cache-Control。

    協商快取

    協商快取就是與服務端協商之後,透過協商結果來判斷是否使用本地快取。

    協商快取可以基於兩種頭部來實現。

    第一種:請求頭部中的 If-Modified-Since 欄位與響應頭部中的 Last-Modified 欄位實現,這兩個欄位的意思是:

    • 響應頭部中的 Last-Modified:標示這個響應資源的最後修改時間;
    • 請求頭部中的 If-Modified-Since:當資源過期了,發現響應頭中具有 Last-Modified 宣告,則再次發起請求的時候帶上 Last-Modified 的時間,伺服器收到請求後發現有 If-Modified-Since 則與被請求資源的最後修改時間進行對比(Last-Modified),如果最後修改時間較新(大),說明資源又被改過,則返回最新資源,HTTP 200 OK;如果最後修改時間較舊(小),說明資源無新修改,響應 HTTP 304 走快取。

    第二種:請求頭部中的 If-None-Match 欄位與響應頭部中的 ETag 欄位,這兩個欄位的意思是:

    • 響應頭部中 Etag:唯一標識響應資源;
    • 請求頭部中的 If-None-Match:當資源過期時,瀏覽器發現響應頭裡有 Etag,則再次向伺服器發起請求時,會將請求頭 If-None-Match 值設定為 Etag 的值。伺服器收到請求後進行比對,如果資源沒有變化返回 304,如果資源變化了返回 200。

    第一種實現方式是基於時間實現的,第二種實現方式是基於一個唯一標識實現的,相對來說後者可以更加準確地判斷檔案內容是否被修改,避免由於時間篡改導致的不可靠問題。

    當使用 ETag 欄位實現的協商快取的過程:

    • 當瀏覽器第一次請求訪問伺服器資源時,伺服器會在返回這個資源的同時,在 Response 頭部加上 ETag 唯一標識,這個唯一標識的值是根據當前請求的資源生成的;

    • 當瀏覽器再次請求訪問伺服器中的該資源時,首先會先檢查強制快取是否過期:

      • 如果沒有過期,則直接使用本地快取;
      • 如果快取過期了,會在 Request 頭部加上 If-None-Match 欄位,該欄位的值就是 ETag 唯一標識;
    • 伺服器再次收到請求後,

      會根據請求中的 If-None-Match 值與當前請求的資源生成的唯一標識進行比較:

      • 如果值相等,則返回 304 Not Modified,不會返回資源
      • 如果不相等,則返回 200 狀態碼和返回資源,並在 Response 頭部加上新的 ETag 唯一標識;
    • 如果瀏覽器收到 304 的請求響應狀態碼,則會從本地快取中載入資源,否則更新資源。

  4. HTTP 如何實現長連線?在什麼時候會超時?

    透過在頭部(請求和響應頭)設定 Connection: keep-alive,HTTP1.0協議支援,但是預設關閉,從HTTP1.1協議以後,連線預設都是長連線

    1、HTTP 一般會有 httpd 守護程式,裡面可以設定 keep-alive timeout,當 tcp 連結閒置超過這個時間就會關閉,也可以在 HTTP 的 header 裡面設定超時時間

    2、TCP 的 keep-alive 包含三個引數,支援在系統核心的 net.ipv4 裡面設定:當 TCP 連結之後,閒置了 tcp_keepalive_time,則會發生偵測包,如果沒有收到對方的 ACK,那麼會每隔 tcp_keepalive_intvl 再發一次,直到傳送了 tcp_keepalive_probes,就會丟棄該連結。

    (1)tcp_keepalive_intvl = 15
    (2)tcp_keepalive_probes = 5
    (3)tcp_keepalive_time = 1800

    實際上 HTTP 沒有長短連結,只有 TCP 有,TCP 長連線可以複用一個 TCP 連結來發起多次 HTTP 請求,這樣可以減少資源消耗,比如一次請求 HTML,可能需要請求後續的 JS/CSS/圖片等

  5. HTTP 1.0/1.1/2.0/3.0的介紹、優點和缺點

    HTTP/1.0

    1996年5月,HTTP/1.0 版本釋出,為了提高系統的效率,HTTP/1.0規定瀏覽器與伺服器只保持短暫的連線,瀏覽器的每次請求都需要與伺服器建立一個TCP連線,伺服器完成請求處理後立即斷開TCP連線,伺服器不跟蹤每個客戶也不記錄過去的請求。

    HTTP/1.0中瀏覽器與伺服器只保持短暫的連線,連線無法複用。也就是說每個TCP連線只能傳送一個請求。傳送資料完畢,連線就關閉,如果還要請求其他資源,就必須再新建一個連線。

    我們知道TCP連線的建立需要三次握手,是很耗費時間的一個過程。所以,HTTP/1.0版本的效能比較差。

    HTTP/1.1

    HTTP 最突出的優點是「簡單、靈活和易於擴充套件、應用廣泛和跨平臺」。

    HTTP 協議裡有優缺點一體的雙刃劍,分別是「無狀態、明文傳輸」,同時還有一大缺點「不安全」。

    為瞭解決HTTP/1.0存在的缺陷,HTTP/1.1於1999年誕生。相比較於HTTP/1.0來說,最主要的改進就是引入了持久連線。所謂的持久連線即TCP連線預設不關閉,可以被多個請求複用

    客戶端和伺服器發現對方一段時間沒有活動,就可以主動關閉連線。或者客戶端在最後一個請求時,主動告訴服務端要關閉連線。

    HTTP/1.1版還引入了管道機制(pipelining),即在同一個TCP連線裡面,客戶端可以同時傳送多個請求。這樣就進一步改進了HTTP協議的效率。

    有了持久連線和管道,大大的提升了HTTP的效率。但是服務端還是順序執行的,效率還有提升的空間。

    HTTP/2

    HTTP/2 是 HTTP 協議自 1999 年 HTTP 1.1 釋出後的首個更新,主要基於 SPDY 協議。

    HTTP/2 為瞭解決HTTP/1.1中仍然存在的效率問題,HTTP/2 採用了多路複用。即在一個連線裡,客戶端和瀏覽器都可以同時傳送多個請求或回應,而且不用按照順序一一對應。能這樣做有一個前提,就是HTTP/2進行了二進位制分幀,即 HTTP/2 會將所有傳輸的資訊分割為更小的訊息和幀(frame),並對它們採用二進位制格式的編碼。

    而這個負責拆分、組裝請求和二進位制幀的一層就叫做二進位制分幀層

    除此之外,還有一些其他的最佳化,比如做Header壓縮、服務端推送等。

    Header壓縮就是壓縮老闆和員工之間的對話。

    服務端推送就是員工事先把一些老闆可能詢問的事情提現傳送到老闆的手機(快取)上。這樣老闆想要知道的時候就可以直接讀取簡訊(快取)了。

    HTTP/2 相比 HTTP/1.1 效能上的改進:

    • 頭部壓縮
    • 二進位制格式
    • 併發傳輸
    • 伺服器主動推送資源

    HTTP/2 有什麼缺陷?

    HTTP/2 透過 Stream 的併發能力,解決了 HTTP/1 隊頭阻塞的問題,看似很完美了,但是 HTTP/2 還是存在“隊頭阻塞”的問題,只不過問題不是在 HTTP 這一層面,而是在 TCP 這一層。

    HTTP/2 是基於 TCP 協議來傳輸資料的,TCP 是位元組流協議,TCP 層必須保證收到的位元組資料是完整且連續的,這樣核心才會將緩衝區裡的資料返回給 HTTP 應用,那麼當「前 1 個位元組資料」沒有到達時,後收到的位元組資料只能存放在核心緩衝區裡,只有等到這 1 個位元組資料到達時,HTTP/2 應用層才能從核心中拿到資料,這就是 HTTP/2 隊頭阻塞問題。

    HTTP3.0

    HTTP/2 雖然具有多個流併發傳輸的能力,但是傳輸層是 TCP 協議,於是存在以下缺陷:

    • 隊頭阻塞,HTTP/2 多個請求跑在一個 TCP 連線中,如果序列號較低的 TCP 段在網路傳輸中丟失了,即使序列號較高的 TCP 段已經被接收了,應用層也無法從核心中讀取到這部分資料,從 HTTP 視角看,就是多個請求被阻塞了;
    • TCP 和 TLS 握手時延,TCP 三次握手和 TLS 四次握手,共有 3-RTT 的時延;
    • 連線遷移需要重新連線,移動裝置從 4G 網路環境切換到 WiFi 時,由於 TCP 是基於四元組來確認一條 TCP 連線的,那麼網路環境變化後,就會導致 IP 地址或埠變化,於是 TCP 只能斷開連線,然後再重新建立連線,切換網路環境的成本高;

    HTTP/3 就將傳輸層從 TCP 替換成了 UDP,並在 UDP 協議上開發了 QUIC 協議,來保證資料的可靠傳輸。

    QUIC 協議的特點:

    • 無隊頭阻塞,QUIC 連線上的多個 Stream 之間並沒有依賴,都是獨立的,也不會有底層協議限制,某個流發生丟包了,只會影響該流,其他流不受影響;
    • 建立連線速度快,因為 QUIC 內部包含 TLS 1.3,因此僅需 1 個 RTT 就可以「同時」完成建立連線與 TLS 金鑰協商,甚至在第二次連線的時候,應用資料包可以和 QUIC 握手資訊(連線資訊 + TLS 資訊)一起傳送,達到 0-RTT 的效果。
    • 連線遷移,QUIC 協議沒有用四元組的方式來“繫結”連線,而是透過「連線 ID 」來標記通訊的兩個端點,客戶端和伺服器可以各自選擇一組 ID 來標記自己,因此即使移動裝置的網路變化後,導致 IP 地址變化了,只要仍保有上下文資訊(比如連線 ID、TLS 金鑰等),就可以“無縫”地複用原連線,消除重連的成本;

    另外 HTTP/3 的 QPACK 透過兩個特殊的單向流來同步雙方的動態表,解決了 HTTP/2 的 HPACK 隊頭阻塞問題。

  6. HTTPS的介紹

    HTTPS 並不是新協議,而是讓 HTTP 先和 SSL(Secure Sockets Layer)通訊,再由 SSL 和 TCP 通訊,也就是說 HTTPS 使用了隧道進行通訊。透過使用 SSL,HTTPS 具有了加密(防竊聽)、認證(防偽裝)和完整性保護(防篡改)。

  7. HTTPS是如何保證資料傳輸的安全,整體的流程是什麼?(SSL是怎麼工作保證安全的)

    (1)客戶端向伺服器端發起SSL連線請求;

    (2) 伺服器把公鑰傳送給客戶端,並且伺服器端儲存著唯一的私鑰

    (3)客戶端用公鑰對雙方通訊的對稱秘鑰進行加密,併傳送給伺服器端

    (4)伺服器利用自己唯一的私鑰對客戶端發來的對稱秘鑰進行解密,

    (5)進行資料傳輸,伺服器和客戶端雙方用公有的相同的對稱秘鑰對資料進行加密解密,可以保證在資料收發過程中的安全,即是第三方獲得資料包,也無法對其進行加密,解密和篡改。

    因為數字簽名、摘要是證書防偽非常關鍵的武器。 “摘要”就是對傳輸的內容,透過hash演演算法計算出一段固定長度的串。透過傳送方的私鑰對這段摘要進行加密,加密後得到的結果就是“數字簽名”

    SSL/TLS協議的基本思路是採用公鑰加密法,也就是說,客戶端先向伺服器端索要公鑰,然後用公鑰加密資訊,伺服器收到密文後,用自己的私鑰解密。

    補充:SSL/TLS的四次握手,目前網上的主流答案都在重複阮一峰老師的部落格,屬於TLS 1.0版本的答案,使用RSA金鑰交換演演算法。但是現在TLS 1.2已經成為主流,使用ECDHE演演算法,如果面試可以說出這個版本的答案,應該會更好。

  8. 什麼是SSL/TLS

    SSL代表安全套接字層。它是一種用於加密和驗證應用程式(如瀏覽器)和Web伺服器之間傳送的資料的協議。 身份驗證 , 加密Https的加密機制是一種共享金鑰加密和公開金鑰加密並用的混合加密機制。

    SSL/TLS協議作用:認證使用者和服務,加密資料,維護資料的完整性的應用層協議加密和解密需要兩個不同的金鑰,故被稱為非對稱加密;加密和解密都使用同一個金鑰的

    對稱加密:優點在於加密、解密效率通常比較高 ,HTTPS 是基於非對稱加密的, 公鑰是公開的。

  9. TLS 握手過程

    TLS 協議是如何解決 HTTP 的風險的呢?

    • 資訊加密: HTTP 互動資訊是被加密的,第三方就無法被竊取;
    • 校驗機制:校驗資訊傳輸過程中是否有被第三方篡改過,如果被篡改過,則會有警告提示;
    • 身份證書:證明淘寶是真的淘寶網;

    TLS 的握手過程,其中每一個「框」都是一個記錄(record),記錄是 TLS 收發資料的基本單位,類似於 TCP 裡的 segment。多個記錄可以組合成一個 TCP 包傳送,所以通常經過「四個訊息」就可以完成 TLS 握手,也就是需要 2個 RTT 的時延,然後就可以在安全的通訊環境裡傳送 HTTP 報文,實現 HTTPS 協議。

    HTTPS 是應用層協議,需要先完成 TCP 連線建立,然後走 TLS 握手過程後,才能建立通訊安全的連線。

  10. HTTPS RSA握手過程

    HTTPS 採用混合的加密機制,使用非對稱金鑰加密用於傳輸對稱金鑰來保證傳輸過程的安全性,之後使用對稱金鑰加密進行通訊來保證通訊過程的效率

    確保傳輸安全過程(其實就是rsa原理):

    1. Client給出協議版本號、一個客戶端生成的隨機數(Client random),以及客戶端支援的加密方法。
    2. Server確認雙方使用的加密方法,並給出數字證書、以及一個伺服器生成的隨機數(Server random)。
    3. Client確認數字證書有效,然後生成呀一個新的隨機數(Premaster secret),並使用數字證書中的公鑰,加密這個隨機數,發給Server。
    4. Server使用自己的私鑰,獲取Client發來的隨機數(Premaster secret)。
    5. Client和Server根據約定的加密方法,使用前面的三個隨機數,生成”對話金鑰”(session key),用來加密接下來的整個對話過程。

    使用 RSA 金鑰協商演演算法的最大問題是不支援前向保密。因為客戶端傳遞隨機數(用於生成對稱加密金鑰的條件之一)給服務端時使用的是公鑰加密的,服務端收到後,會用私鑰解密得到隨機數。所以一旦服務端的私鑰洩漏了,過去被第三方截獲的所有 TLS 通訊密文都會被破解。

    為瞭解決這個問題,後面就出現了 ECDHE 金鑰協商演演算法。

  11. HTTPS ECDHE握手過程

    ECDHE 演演算法是在 DHE 演演算法的基礎上利用了 ECC 橢圓曲線特性,可以用更少的計算量計算出公鑰,以及最終的會話金鑰。

    TLS 第一次握手

    客戶端首先會發一個「Client Hello」訊息,訊息裡面有客戶端使用的 TLS 版本號、支援的密碼套件列表,以及生成的隨機數(*Client Random*)

    TLS 第二次握手

    服務端收到客戶端的「打招呼」,同樣也要回禮,會返回「Server Hello」訊息,訊息面有伺服器確認的 TLS 版本號,也給出了一個隨機數(*Server Random*),然後從客戶端的密碼套件列表選擇了一個合適的密碼套件。

    接著,服務端為了證明自己的身份,傳送「Certificate」訊息,會把證書也發給客戶端。

    這一步就和 RSA 握手過程有很大的區別了,因為服務端選擇了 ECDHE 金鑰協商演演算法,所以會在傳送完證書後,傳送「Server Key Exchange」訊息。

    這個過程伺服器做了三件事:

    • 選擇了名為 x25519 的橢圓曲線,選好了橢圓曲線相當於橢圓曲線基點 G 也定好了,這些都會公開給客戶端;
    • 生成隨機數作為服務端橢圓曲線的私鑰,保留到本地;
    • 根據基點 G 和私鑰計算出服務端的橢圓曲線公鑰,這個會公開給客戶端。

    為了保證這個橢圓曲線的公鑰不被第三方篡改,服務端會用 RSA 簽名演演算法給服務端的橢圓曲線公鑰做個簽名。

    隨後,就是「Server Hello Done」訊息,服務端跟客戶端表明:“這些就是我提供的資訊,打招呼完畢”。

    至此,TLS 兩次握手就已經完成了,目前客戶端和服務端透過明文共享了這幾個資訊:Client Random、Server Random 、使用的橢圓曲線、橢圓曲線基點 G、服務端橢圓曲線的公鑰,這幾個資訊很重要,是後續生成會話金鑰的材料。

    TLS 第三次握手

    客戶端收到了服務端的證書後,自然要校驗證書是否合法,如果證書合法,那麼服務端到身份就是沒問題的。校驗證書的過程會走證書鏈逐級驗證,確認證書的真實性,再用證書的公鑰驗證簽名,這樣就能確認服務端的身份了,確認無誤後,就可以繼續往下走。

    客戶端會生成一個隨機數作為客戶端橢圓曲線的私鑰,然後再根據服務端前面給的資訊,生成客戶端的橢圓曲線公鑰,然後用「Client Key Exchange」訊息發給服務端。

    算好會話金鑰後,客戶端會發一個「Change Cipher Spec」訊息,告訴服務端後續改用對稱演演算法加密通訊。

    接著,客戶端會發「Encrypted Handshake Message」訊息,把之前傳送的資料做一個摘要,再用對稱金鑰加密一下,讓服務端做個驗證,驗證下本次生成的對稱金鑰是否可以正常使用。

    TLS 第四次握手

    最後,服務端也會有一個同樣的操作,發「Change Cipher Spec」和「Encrypted Handshake Message」訊息,如果雙方都驗證加密和解密沒問題,那麼握手正式完成。於是,就可以正常收發加密的 HTTP 請求和響應了。

  12. RSA 和 ECDHE 握手過程的區別

    • RSA 金鑰協商演演算法「不支援」前向保密,ECDHE 金鑰協商演演算法「支援」前向保密;
    • 使用了 RSA 金鑰協商演演算法,TLS 完成四次握手後,才能進行應用資料傳輸,而對於 ECDHE 演演算法,客戶端可以不用等服務端的最後一次 TLS 握手,就可以提前發出加密的 HTTP 資料,節省了一個訊息的往返時間(這個是 RFC 檔案規定的,具體原因檔案沒有說明,所以這點我也不太明白);
    • 使用 ECDHE, 在 TLS 第 2 次握手中,會出現伺服器端發出的「Server Key Exchange」訊息,而 RSA 握手過程沒有該訊息;
  13. FIN_WAIT_2,CLOSE_WAIT狀態和TIME_WAIT狀態

    • FIN_WAIT_2:
      • 半關閉狀態。
      • 傳送斷開請求一方還有接收資料能力,但已經沒有傳送資料能力。
    • CLOSE_WAIT狀態:
      • 被動關閉連線一方接收到FIN包會立即回應ACK包表示已接收到斷開請求。
      • 被動關閉連線一方如果還有剩餘資料要傳送就會進入CLOSE_WAIT狀態。
    • TIME_WAIT狀態:
      • 又叫2MSL等待狀態。
      • 如果客戶端直接進入CLOSED狀態,如果服務端沒有接收到最後一次ACK包會在超時之後重新再發FIN包,此時因為客戶端已經CLOSED,所以服務端就不會收到ACK而是收到RST。所以TIME_WAIT狀態目的是防止最後一次握手資料沒有到達對方而觸發重傳FIN準備的。
      • 在2MSL時間內,同一個socket不能再被使用,否則有可能會和舊連線資料混淆(如果新連線和舊連線的socket相同的話)。
  14. 對稱金鑰加密和非對稱金鑰加密

    對稱秘鑰加密

    對稱金鑰加密(Symmetric-Key Encryption),加密和解密使用同一金鑰。

    • 優點:運算速度快
    • 缺點:無法安全地將金鑰傳輸給通訊方

    非對稱秘鑰加密

    非對稱金鑰加密,又稱公開金鑰加密(Public-Key Encryption),加密和解密使用不同的金鑰。

    公開金鑰所有人都可以獲得,通訊傳送方獲得接收方的公開金鑰之後,就可以使用公開金鑰進行加密接收方收到通訊內容後使用私有金鑰解密

    非對稱金鑰除了用來加密,還可以用來進行簽名。因為私有金鑰無法被其他人獲取,因此通訊傳送方使用其私有金鑰進行簽名,通訊接收方使用傳送方的公開金鑰對簽名進行解密,就能判斷這個簽名是否正確。

    • 優點:可以更安全地將公開金鑰傳輸給通訊傳送方;
    • 缺點:運算速度慢。
  15. HTTPS如何最佳化

    對於硬體最佳化的方向,因為 HTTPS 是屬於計算密集型,應該選擇計算力更強的 CPU,而且最好選擇支援 AES-NI 特性的 CPU,這個特性可以在硬體級別最佳化 AES 對稱加密演演算法,加快應用資料的加解密。

    對於軟體最佳化的方向,如果可以,把軟體升級成較新的版本,比如將 Linux 核心 2.X 升級成 4.X,將 openssl 1.0.1 升級到 1.1.1,因為新版本的軟體不僅會提供新的特性,而且還會修復老版本的問題。

    對於協議最佳化的方向:

    • 金鑰交換演演算法應該選擇 ECDHE 演演算法,而不用 RSA 演演算法,因為 ECDHE 演演算法具備前向安全性,而且客戶端可以在第三次握手之後,就傳送加密應用資料,節省了 1 RTT。
    • 將 TLS1.2 升級 TLS1.3,因為 TLS1.3 的握手過程只需要 1 RTT,而且安全性更強。

    對於證書最佳化的方向:

    • 伺服器應該選用 ECDSA 證書,而非 RSA 證書,因為在相同安全級別下,ECC 的金鑰長度比 RSA 短很多,這樣可以提高證書傳輸的效率;
    • 伺服器應該開啟 OCSP Stapling 功能,由伺服器預先獲得 OCSP 的響應,並把響應結果快取起來,這樣 TLS 握手的時候就不用再訪問 CA 伺服器,減少了網路通訊的開銷,提高了證書驗證的效率;

    對於重連 HTTPS 時,我們可以使用一些技術讓客戶端和服務端使用上一次 HTTPS 連線使用的會話金鑰,直接恢復會話,而不用再重新走完整的 TLS 握手過程。

    常見的會話重用技術有 Session ID 和 Session Ticket,用了會話重用技術,當再次重連 HTTPS 時,只需要 1 RTT 就可以恢復會話。對於 TLS1.3 使用 Pre-shared Key 會話重用技術,只需要 0 RTT 就可以恢復會話。

    這些會話重用技術雖然好用,但是存在一定的安全風險,它們不僅不具備前向安全,而且有重放攻擊的風險,所以應當對會話金鑰設定一個合理的過期時間。

  16. WebSocket協議

    websocket是一種瀏覽器與伺服器進行全雙工通訊的網路技術,屬於 應用層協議。它 基於TCP傳輸協議,並 複用HTTP 的握手通道,用來彌補HTTP協議在持久通訊能力上的不足。

    • ws 預設埠:80
    • wss 預設埠:443
    • Websocket 透過HTTP協議握手

    websocket的特點有哪些?

    1. 節省資源開銷,HTTP請求每次都要攜帶完整的頭部,此項開銷顯著減少了;
    2. 更強的實時性,由於協議是全雙工通訊,所以伺服器可以主動給客戶端推送資料,相對於HTTP請求需要等待客戶端發起請求服務端才能響應,延遲明顯更少;
    3. 保持連線狀態,能夠記錄使用者狀態,通訊時可以省略部分狀態資訊,不像HTTP每次都需要攜帶使用者認證資訊;
    4. 更好的二進位制支援,Websocket定義了二進位制幀,相對HTTP,可以更輕鬆地處理二進位制內容。
  17. HTTP如何實現長連線

    HTTP長連線

    • 瀏覽器向伺服器進行一次HTTP會話訪問後,並不會直接關閉這個連線,而是會預設保持一段時間,那麼下一次瀏覽器繼續訪問的時候就會再次利用到這個連線。
    • HTTP/1.1版本中,預設的連線都是長連線,我們可以透過Connection: keep-alive欄位進行指定。

    TCP保活機制

    • 為什麼要有保活機制?

      • 第一點自然是我們這篇文章的主題,透過保活機制,我們可以保證通訊雙方的連線不被釋放掉
      • 第二點就是在另一些情況下,如果客戶端或者伺服器發生了錯誤或者當機,那麼就可以依靠這種保活機制探測出網路通訊出現了問題,進而可以釋放掉這種錯誤連線。
    • 保活機制

      首先保活機制的工作原理就是,透過在伺服器端設定一個保活定時器,當定時器開始工作後就定時的向網路通訊的另一端發出保活探測的TCP報文,如果接收到了ACK報文,那麼就證明對方存活,可以繼續保有連線;否則就證明網路存在故障。

      上面只是在原理層面簡單的介紹,根據文獻[1],我們可以瞭解到詳細的內容:

      • 如果一個給定的連線在兩個小時之內沒有任何動作,則伺服器就向客戶傳送一個探查報文段。客戶主機必須處於以下 4個狀態之一。
      • 狀態1:客戶主機依然正常執行,並從伺服器可達。客戶的TCP響應正常,而伺服器也知道對方是正常工作的。伺服器在兩小時以後將保活定時器復位。如果在兩個小時定時器到時間之前有應用程式的通訊量透過此連線,則定時器在交換資料後的未來2小時再復位。
      • 狀態2:客戶主機已經崩潰,並且關閉或者正在重新啟動。在任何一種情況下,客戶的TCP都沒有響應。伺服器將不能夠收到對探查的響應,並在75秒後超時。伺服器總共傳送10個這樣的探查,每個間隔75秒。如果伺服器沒有收到一個響應,它就認為客戶主機已經關閉並終止連線。
      • 狀態3:客戶主機崩潰並已經重新啟動。這時伺服器將收到一個對其保活探查的響應,但是這個響應是一個復位,使得伺服器終止這個連線。
      • 狀態4:客戶主機正常執行,但是從伺服器不可達。這與狀態2相同,因為TCP不能夠區分狀態4與狀態2之間的區別,它所能發現的就是沒有收到探查的響應。
  18. HTTP和HTTPS的區別

    Http協議執行在TCP之上,明文傳輸,客戶端與伺服器端都無法驗證對方的身份;Https是身披SSL(Secure Socket Layer)外殼的Http,執行於SSL上,SSL執行於TCP之上,是新增了加密和認證機制的HTTP。二者之間存在如下不同:

    1、埠不同:Http與Https使用不同的連線方式,用的埠也不一樣,前者是80,後者是443;

    2、資源消耗:和HTTP通訊相比,Https通訊會由於加減密處理消耗更多的CPU和記憶體資源;

    3、開銷:Https通訊需要證書,而證書一般需要向認證機構購買;

    4、安全性:HTTP 的連線很簡單,是無狀態的;HTTPS 協議是由 TLS+HTTP 協議構建的可進行加密傳輸、身份認證的網路協議,比 HTTP 協議安全 
    Https的加密機制是一種共享金鑰加密和公開金鑰加密並用的混合加密機制。

    websocket應用場景有哪些?

    • 即時通訊、直播、遊戲、線上協同工具(騰訊檔案等)、實時資料拉取和推送地圖
  19. HTTP請求方法有多少

    客戶端傳送的 請求報文 第一行為請求行,包含了方法欄位。

    根據 HTTP 標準,HTTP 請求可以使用多種請求方法。

    HTTP1.0 定義了三種請求方法: GET, POST 和 HEAD方法。

    HTTP1.1 新增六種請求方法:OPTIONS、PUT、PATCH、DELETE、TRACE 和 CONNECT 方法。

    序 號 方法 描述
    1 GET 請求指定的頁面資訊,並返回實體主體。
    2 HEAD 類似於 GET 請求,只不過返回的響應中沒有具體的內容,用於獲取報頭
    3 POST 向指定資源提交資料進行處理請求(例如提交表單或者上傳檔案)。資料被包含在請求體中。POST 請求可能會導致新的資源的建立和/或已有資源的修改。
    4 PUT 從客戶端向伺服器傳送的資料取代指定的檔案的內容。
    5 DELETE 請求伺服器刪除指定的頁面。
    6 CONNECT HTTP/1.1 協議中預留給能夠將連線改為管道方式的代理伺服器。
    7 OPTIONS 允許客戶端檢視伺服器的效能。
    8 TRACE 回顯伺服器收到的請求,主要用於測試或診斷。
    9 PATCH 是對 PUT 方法的補充,用來對已知資源進行區域性更新 。

3. TCP三次握手/四次揮手

  1. TCP三次握手和四次揮手的過程

    三次握手過程

    • 初始狀態:客戶端處於 closed(關閉)狀態,伺服器處於 listen(監聽) 狀態。
    • 第一次握手:客戶端傳送請求報文將 SYN = 1同步序列號和初始化序列號seq = x傳送給服務端,傳送完之後客戶端處於SYN_Send狀態。(驗證了客戶端的傳送能力和服務端的接收能力)
    • 第二次握手:服務端受到 SYN 請求報文之後,如果同意連線,會以自己的同步序列號SYN(服務端) = 1、初始化序列號 seq = y和確認序列號(期望下次收到的資料包)ack = x+ 1 以及確認號ACK = 1報文作為應答,伺服器為SYN_Receive狀態。(問題來了,兩次握手之後,站在客戶端角度上思考:我傳送和接收都ok,服務端的傳送和接收也都ok。但是站在服務端的角度思考:哎呀,我服務端接收ok,但是我不清楚我的傳送ok不ok呀,而且我還不知道你接受能力如何呢?所以老哥,你需要給我三次握手來傳個話告訴我一聲。你要是不告訴我,萬一我認為你跑了,然後我可能出於安全性的考慮繼續給你發一次,看看你回不回我。)
    • 第三次握手: 客戶端接收到服務端的 SYN + ACK之後,知道可以下次可以傳送了下一序列的資料包了,然後傳送同步序列號 ack = y + 1和資料包的序列號 seq = x + 1以及確認號ACK = 1確認包作為應答,客戶端轉為established狀態。(分別站在雙方的角度上思考,各自ok)

    為什麼需要三次握手,兩次不行嗎

    弄清這個問題,我們需要先弄明白三次握手的目的是什麼,能不能只用兩次握手來達到同樣的目的。

    • 第一次握手:客戶端傳送網路包,服務端收到了。 這樣服務端就能得出結論:客戶端的傳送能力、服務端的接收能力是正常的。
    • 第二次握手:服務端發包,客戶端收到了。 這樣客戶端就能得出結論:服務端的接收、傳送能力,客戶端的接收、傳送能力是正常的。不過此時伺服器並不能確認客戶端的接收能力是否正常。
    • 第三次握手:客戶端發包,服務端收到了。 這樣服務端就能得出結論:客戶端的接收、傳送能力正常,伺服器自己的傳送、接收能力也正常。

    三個方面分析三次握手的原因:

    • 三次握手才可以阻止重複歷史連線的初始化(主要原因)
    • 三次握手才可以同步雙方的初始序列號
    • 三次握手才可以避免資源浪費

    TCP 建立連線時,透過三次握手能防止歷史連線的建立,能減少雙方不必要的資源開銷,能幫助雙方同步初始化序列號。序列號能夠保證資料包不重複、不丟棄和按序傳輸。

    不使用「兩次握手」和「四次握手」的原因:

    • 「兩次握手」:無法防止歷史連線的建立,會造成雙方資源的浪費,也無法可靠的同步雙方序列號;
    • 「四次握手」:三次握手就已經理論上最少可靠連線建立,所以不需要使用更多的通訊次數。

    四次揮手過程

    • 初始化狀態:客戶端和服務端都在連線狀態,接下來開始進行四次分手斷開連線操作。
    • 第一次分手:第一次分手無論是客戶端還是服務端都可以發起,因為 TCP 是全雙工的。

    假如客戶端傳送的資料已經傳送完畢,傳送FIN = 1 告訴服務端,客戶端所有資料已經全發完了服務端你可以關閉接收了,但是如果你們服務端有資料要發給客戶端,客戶端照樣可以接收的。此時客戶端處於FIN = 1等待服務端確認釋放連線狀態。

    • 第二次分手:服務端接收到客戶端的釋放請求連線之後,知道客戶端沒有資料要發給自己了然後服務端傳送ACK = 1告訴客戶端收到你發給我的資訊,此時服務端處於 CLOSE_WAIT 等待關閉狀態。(服務端先回應給客戶端一聲,我知道了,但服務端的傳送資料能力即將等待關閉,於是接下來第三次就來了。)
    • 第三次分手:此時服務端向客戶端把所有的資料傳送完了,然後傳送一個FIN = 1,用於告訴客戶端,服務端的所有資料傳送完畢客戶端你也可以關閉接收資料連線了。此時服務端狀態處於LAST_ACK狀態,來等待確認客戶端是否收到了自己的請求。(服務端等客戶端回覆是否收到呢,不收到的話,服務端不知道客戶端是不是掛掉了還是咋回事呢,所以服務端不敢關閉自己的接收能力,於是第四次就來了。)
    • 第四次分手:此時如果客戶端收到了服務端傳送完的資訊之後,就傳送ACK = 1,告訴服務端,客戶端已經收到了你的資訊。有一個 2 MSL 的延遲等待

    為什麼需要揮手四次

    因為當服務端收到客戶端的SYN連線請求報文後,可以直接傳送SYN+ACK報文。其中ACK報文是用來應答的,SYN報文是用來同步的。但是關閉連線時,當服務端收到FIN報文時,很可能並不會立即關閉SOCKET,所以只能先回復一個ACK報文,告訴客戶端,"你發的FIN報文收到了"。只有等到我服務端所有的報文都傳送完了,我才能傳送FIN報文,因此不能一起傳送。故需要四次揮手。

  2. TCP協議介紹

    TCP(Transmission Control Protocol 傳輸控制協議)是一種面向連線的、可靠的、基於位元組流的傳輸層通訊協議。

    特點

    • TCP是面向連線的
    • 每一條TCP連線只能有兩個端點,每一條TCP連線只能是點對點的(一對一);
    • TCP提供可靠交付的服務。透過TCP連線傳送的資料,無差錯、不丟失、不重複、並且按序到達;
    • TCP提供全雙工通訊。TCP允許通訊雙方的應用程式在任何時候都能傳送資料。TCP連線的兩端都設有傳送快取和接收快取,用來臨時存放雙方通訊的資料;
    • 面向位元組流。TCP中的“流”(stream)指的是流入程式或從程式流出的位元組序列。“面向位元組流”的含義是:雖然應用程式和TCP的互動是一次一個資料塊(大小不等),但TCP把應用程式交下來的資料僅僅看成是一連串的無結構的位元組流。
  3. TCP三次握手、四次揮手丟失,會發生什麼

    三次握手丟失

    第一次握手丟失了,會發生什麼?

    如果客戶端遲遲收不到服務端的 SYN-ACK 報文(第二次握手),就會觸發「超時重傳」機制,重傳 SYN 報文,而且重傳的 SYN 報文的序列號都是一樣的每次超時的時間是上一次的 2 倍

    第二次握手丟失了,會發生什麼?

    因為第二次握手報文裡是包含對客戶端的第一次握手的 ACK 確認報文,所以,如果客戶端遲遲沒有收到第二次握手,那麼客戶端就覺得可能自己的 SYN 報文(第一次握手)丟失了,於是客戶端就會觸發超時重傳機制,重傳 SYN 報文

    然後,因為第二次握手中包含服務端的 SYN 報文,所以當客戶端收到後,需要給服務端傳送 ACK 確認報文(第三次握手),服務端才會認為該 SYN 報文被客戶端收到了。

    那麼,如果第二次握手丟失了,服務端就收不到第三次握手,於是服務端這邊會觸發超時重傳機制,重傳 SYN-ACK 報文

    因此,當第二次握手丟失了,客戶端和服務端都會重傳

    第三次握手丟失了,會發生什麼?

    客戶端收到服務端的 SYN-ACK 報文後,就會給服務端回一個 ACK 報文,也就是第三次握手,此時客戶端狀態進入到 ESTABLISH 狀態。

    因為這個第三次握手的 ACK 是對第二次握手的 SYN 的確認報文,所以當第三次握手丟失了,如果服務端那一方遲遲收不到這個確認報文,就會觸發超時重傳機制,重傳 SYN-ACK 報文,直到收到第三次握手,或者達到最大重傳次數。

    注意,ACK 報文是不會有重傳的,當 ACK 丟失了,就由對方重傳對應的報文

    揮手四次丟失

    第一次揮手丟失了,會發生什麼?

    如果第一次揮手丟失了,那麼客戶端遲遲收不到被動方的 ACK 的話,也就會觸發超時重傳機制,重傳 FIN 報文,重發次數由 tcp_orphan_retries 引數控制。

    當客戶端重傳 FIN 報文的次數超過 tcp_orphan_retries 後,就不再傳送 FIN 報文,則會在等待一段時間(時間為上一次超時時間的 2 倍),如果還是沒能收到第二次揮手,那麼直接進入到 close 狀態。

    第二次揮手丟失了,會發生什麼?

    當服務端收到客戶端的第一次揮手後,就會先回一個 ACK 確認報文,此時服務端的連線進入到 CLOSE_WAIT 狀態。

    在前面我們也提了,ACK 報文是不會重傳的,所以如果服務端的第二次揮手丟失了,客戶端就會觸發超時重傳機制,重傳 FIN 報文,直到收到服務端的第二次揮手,或者達到最大的重傳次數。

    第三次揮手丟失了,會發生什麼?

    當服務端(被動關閉方)收到客戶端(主動關閉方)的 FIN 報文後,核心會自動回覆 ACK,同時連線處於 CLOSE_WAIT 狀態,顧名思義,它表示等待應用程式呼叫 close 函式關閉連線。

    此時,核心是沒有權利替代程式關閉連線,必須由程式主動呼叫 close 函式來觸發服務端傳送 FIN 報文。

    服務端處於 CLOSE_WAIT 狀態時,呼叫了 close 函式,核心就會發出 FIN 報文,同時連線進入 LAST_ACK 狀態,等待客戶端返回 ACK 來確認連線關閉。

    如果遲遲收不到這個 ACK,服務端就會重發 FIN 報文,重發次數仍然由 tcp_orphan_retries 引數控制,這與客戶端重發 FIN 報文的重傳次數控制方式是一樣的。

    第四次揮手丟失了,會發生什麼?

    當客戶端收到服務端的第三次揮手的 FIN 報文後,就會回 ACK 報文,也就是第四次揮手,此時客戶端連線進入 TIME_WAIT 狀態。

    在 Linux 系統,TIME_WAIT 狀態會持續 2MSL 後才會進入關閉狀態。

    然後,服務端(被動關閉方)沒有收到 ACK 報文前,還是處於 LAST_ACK 狀態。

    如果第四次揮手的 ACK 報文沒有到達服務端,服務端就會重發 FIN 報文,重發次數仍然由前面介紹過的 tcp_orphan_retries 引數控制。

  4. 2MSL等待狀態

    2MSL等待狀態

    TIME_WAIT狀態也成為2MSL等待狀態。每個具體TCP實現必須選擇一個報文段最大生存時間MSL(Maximum Segment Lifetime),它是任何報文段被丟棄前在網路內的最長時間。這個時間是有限的,因為TCP報文段以IP資料包在網路內傳輸,而IP資料包則有限制其生存時間的TTL欄位。

    對一個具體實現所給定的MSL值,處理的原則是:當TCP執行一個主動關閉,併發回最後一個ACK,該連線必須在TIME_WAIT狀態停留的時間為2倍的MSL。這樣可讓TCP再次傳送最後的ACK以防這個ACK丟失(另一端超時並重發最後的FIN)。

    這種2MSL等待的另一個結果是這個TCP連線在2MSL等待期間,定義這個連線的插口(客戶的IP地址和埠號,伺服器的IP地址和埠號)不能被使用。這個連線只能在2MSL結束後才能再被使用。

    為什麼TIME_WAIT狀態需要經過2MSL才能返回到CLOSE狀態

    理論上,四個報文都傳送完畢,就可以直接進入CLOSE狀態了,但是可能網路是不可靠的,有可能最後一個ACK丟失。所以TIME_WAIT狀態就是用來重發可能丟失的ACK報文

    客戶端給服務端傳送的ACK = 1丟失,服務端等待 1MSL沒收到然後重新傳送訊息需要1MSL。如果再次接收到服務端的訊息,則重啟2MSL計時器傳送確認請求。客戶端只需等待2MSL,如果沒有再次收到服務端的訊息,就說明服務端已經接收到自己確認訊息;此時雙方都關閉的連線,TCP 四次分手完畢

  5. TIME_WAIT介紹

    MSL 是 Maximum Segment Lifetime,報文最大生存時間,它是任何報文在網路上存在的最長時間,超過這個時間報文將被丟棄。因為 TCP 報文基於是 IP 協議的,而 IP 頭中有一個 TTL 欄位,是 IP 資料包可以經過的最大路由數,每經過一個處理他的路由器此值就減 1,當此值為 0 則資料包將被丟棄,同時傳送 ICMP 報文通知源主機。

    MSL 與 TTL 的區別: MSL 的單位是時間,而 TTL 是經過路由跳數。所以 MSL 應該要大於等於 TTL 消耗為 0 的時間,以確保報文已被自然消亡。

    TTL 的值一般是 64,Linux 將 MSL 設定為 30 秒,意味著 Linux 認為資料包文經過 64 個路由器的時間不會超過 30 秒,如果超過了,就認為報文已經消失在網路中了

    TIME_WAIT 等待 2 倍的 MSL,比較合理的解釋是: 網路中可能存在來自傳送方的資料包,當這些傳送方的資料包被接收方處理後又會向對方傳送響應,所以一來一回需要等待 2 倍的時間

    為什麼需要 TIME_WAIT 狀態?

    主動發起關閉連線的一方,才會有 TIME-WAIT 狀態。

    需要 TIME-WAIT 狀態,主要是兩個原因:

    • 防止歷史連線中的資料,被後面相同四元組的連線錯誤的接收;
    • 保證「被動關閉連線」的一方,能被正確的關閉;
  6. TIME_WAIT 過多有什麼危害?

    過多的 TIME-WAIT 狀態主要的危害有兩種:

    • 第一是佔用系統資源,比如檔案描述符、記憶體資源、CPU 資源、執行緒資源等;
    • 第二是佔用埠資源,埠資源也是有限的,一般可以開啟的埠為 32768~61000,也可以透過 net.ipv4.ip_local_port_range引數指定範圍。
  7. 如何最佳化 TIME_WAIT?

    這裡給出最佳化 TIME-WAIT 的幾個方式,都是有利有弊:

    • 開啟 net.ipv4.tcp_tw_reuse 和 net.ipv4.tcp_timestamps 選項;
    • net.ipv4.tcp_max_tw_buckets
    • 程式中使用 SO_LINGER ,應用強制使用 RST 關閉。
  8. 什麼是半連線佇列

    伺服器第一次收到客戶端的 SYN 之後,就會處於 SYN_RCVD 狀態,此時雙方還沒有完全建立其連線,伺服器會把此種狀態下請求連線放在一個佇列裡,我們把這種佇列稱之為半連線佇列

    當然還有一個全連線佇列,就是已經完成三次握手,建立起連線的就會放在全連線佇列中。如果佇列滿了就有可能會出現丟包現象。

    這裡在補充一點關於SYN-ACK 重傳次數的問題: 伺服器傳送完SYN-ACK包,如果未收到客戶確認包,伺服器進行首次重傳,等待一段時間仍未收到客戶確認包,進行第二次重傳。如果重傳次數超過系統規定的最大重傳次數,系統將該連線資訊從半連線佇列中刪除。 注意,每次重傳等待的時間不一定相同,一般會是指數增長,例如間隔時間為 1s,2s,4s,8s......

  9. 常見TCP的連線狀態有哪些

    • CLOSED:初始狀態。
    • LISTEN:伺服器處於監聽狀態。
    • SYN_SEND:客戶端socket執行CONNECT連線,傳送SYN包,進入此狀態。
    • SYN_RECV:服務端收到SYN包併傳送服務端SYN包,進入此狀態。
    • ESTABLISH:表示連線建立。客戶端傳送了最後一個ACK包後進入此狀態,服務端接收到ACK包後進入此狀態。
    • FIN_WAIT_1:終止連線的一方(通常是客戶機)傳送了FIN報文後進入。等待對方FIN。
    • CLOSE_WAIT:(假設伺服器)接收到客戶機FIN包之後等待關閉的階段。在接收到對方的FIN包之後,自然是需要立即回覆ACK包的,表示已經知道斷開請求。但是本方是否立即斷開連線(傳送FIN包)取決是否還有資料需要傳送給客戶端,若有,則在傳送FIN包之前均為此狀態。
    • FIN_WAIT_2:此時是半連線狀態,即有一方要求關閉連線,等待另一方關閉。客戶端接收到伺服器的ACK包,但並沒有立即接收到服務端的FIN包,進入FIN_WAIT_2狀態。
    • LAST_ACK:服務端發動最後的FIN包,等待最後的客戶端ACK響應,進入此狀態。
    • TIME_WAIT:客戶端收到服務端的FIN包,並立即發出ACK包做最後的確認,在此之後的2MSL時間稱為TIME_WAIT狀態。
  10. TCP頭部中有哪些資訊

    • 序號(32bit):傳輸方向上位元組流的位元組編號。初始時序號會被設定一個隨機的初始值(ISN),之後每次傳送資料時,序號值 = ISN + 資料在整個位元組流中的偏移。假設A -> B且ISN = 1024,第一段資料512位元組已經到B,則第二段資料傳送時序號為1024 + 512。用於解決網路包亂序問題。
    • 確認號(32bit):接收方對傳送方TCP報文段的響應,其值是收到的序號值 + 1。
    • 首部長(4bit):標識首部有多少個4位元組 * 首部長,最大為15,即60位元組。
    • 標誌位(6bit):
      • URG:標誌緊急指標是否有效。
      • ACK:標誌確認號是否有效(確認報文段)。用於解決丟包問題。
      • PSH:提示接收端立即從緩衝讀走資料。
      • RST:表示要求對方重新建立連線(復位報文段)。
      • SYN:表示請求建立一個連線(連線報文段)。
      • FIN:表示關閉連線(斷開報文段)。
    • 視窗(16bit):接收視窗。用於告知對方(傳送方)本方的緩衝還能接收多少位元組資料。用於解決流控。
    • 校驗和(16bit):接收端用CRC檢驗整個報文段有無損壞。
  11. RTO,RTT和超時重傳分別是什麼

    • 超時重傳:傳送端傳送報文後若長時間未收到確認的報文則需要重發該報文。可能有以下幾種情況:
      • 傳送的資料沒能到達接收端,所以對方沒有響應。
      • 接收端接收到資料,但是ACK報文在返回過程中丟失。
      • 接收端拒絕或丟棄資料。
    • RTO:從上一次傳送資料,因為長期沒有收到ACK響應,到下一次重發之間的時間。就是重傳間隔。
      • 通常每次重傳RTO是前一次重傳間隔的兩倍,計量單位通常是RTT。例:1RTT,2RTT,4RTT,8RTT......
      • 重傳次數到達上限之後停止重傳。
    • RTT:資料從傳送到接收到對方響應之間的時間間隔,即資料包在網路中一個往返用時。大小不穩定。
  12. TCP重傳

    TCP 實現可靠傳輸的方式之一,是透過序列號與確認應答。

    在 TCP 中,當傳送端的資料到達接收主機時,接收端主機會返回一個確認應答訊息,表示已收到訊息。

    常見的重傳機制:

    • 超時重傳
    • 快速重傳
    • SACK
    • D-SACK

    超時重傳

    重傳機制的其中一個方式,就是在傳送資料時,設定一個定時器,當超過指定的時間後,沒有收到對方的 ACK 確認應答報文,就會重發該資料,也就是我們常說的超時重傳

    TCP 會在以下兩種情況發生超時重傳:

    • 資料包丟失
    • 確認應答丟失

    RTT 指的是資料傳送時刻到接收到確認的時刻的差值,也就是包的往返時間。

    超時重傳時間是以 RTO (Retransmission Timeout 超時重傳時間)表示。

    • 當超時時間 RTO 較大時,重發就慢,丟了老半天才重發,沒有效率,效能差;
    • 當超時時間 RTO 較小時,會導致可能並沒有丟就重發,於是重發的就快,會增加網路擁塞,導致更多的超時,更多的超時導致更多的重發。

    根據上述的兩種情況,我們可以得知,超時重傳時間 RTO 的值應該略大於報文往返 RTT 的值

    快速重傳

    TCP 還有另外一種快速重傳(Fast Retransmit)機制,它不以時間為驅動,而是以資料驅動重傳

    快速重傳的工作方式是當收到三個相同的 ACK 報文時,會在定時器過期之前,重傳丟失的報文段。

    快速重傳機制只解決了一個問題,就是超時時間的問題,但是它依然面臨著另外一個問題。就是重傳的時候,是重傳一個,還是重傳所有的問題。

    SACK 方法

    還有一種實現重傳機制的方式叫:SACK( Selective Acknowledgment), 選擇性確認

    這種方式需要在 TCP 頭部「選項」欄位里加一個 SACK 的東西,它可以將已收到的資料的資訊傳送給「傳送方」,這樣傳送方就可以知道哪些資料收到了,哪些資料沒收到,知道了這些資訊,就可以只重傳丟失的資料

    Duplicate SACK

    Duplicate SACK 又稱 D-SACK,其主要使用了 SACK 來告訴「傳送方」有哪些資料被重複接收了。

    D-SACK 有這麼幾個好處:

    1. 可以讓「傳送方」知道,是發出去的包丟了,還是接收方回應的 ACK 包丟了;
    2. 可以知道是不是「傳送方」的資料包被網路延遲了;
    3. 可以知道網路中是不是把「傳送方」的資料包給複製了;

    在 Linux 下可以透過 net.ipv4.tcp_dsack 引數開啟/關閉這個功能(Linux 2.4 後預設開啟)。

  13. TCP滑動視窗

    TCP 利用滑動視窗實現流量控制的機制。滑動視窗(Sliding window)是一種流量控制技術。早期的網路通訊中,通訊雙方不會考慮網路的擁擠情況直接傳送資料。由於大家不知道網路擁塞狀況,同時傳送資料,導致中間節點阻塞掉包,誰也發不了資料,就有了滑動視窗機制來解決此問題。

    TCP 中採用滑動視窗來進行傳輸控制,滑動視窗的大小意味著接收方還有多大的緩衝區可以用於接收資料。傳送方可以透過滑動視窗的大小來確定應該傳送多少位元組的資料。當滑動視窗為 0 時,傳送方一般不能再傳送資料包,但有兩種情況除外,一種情況是可以傳送緊急資料,例如,允許使用者終止在遠端機上的執行程式。另一種情況是傳送方可以傳送一個 1 位元組的資料包來通知接收方重新宣告它希望接收的下一位元組及傳送方的滑動視窗大小。

  14. TCP流量控制

    TCP 利用滑動視窗實現流量控制。流量控制是為了控制傳送方傳送速率,保證接收方來得及接收。接收方傳送的確認報文中的視窗欄位可以用來控制傳送方視窗大小,從而影響傳送方的傳送速率。將視窗欄位設定為 0,則傳送方不能傳送資料。

    1. 目的是接收方透過TCP頭視窗欄位告知傳送方本方可接收的最大資料量,用以解決傳送速率過快導致接收方不能接收的問題。所以流量控制是點對點控制。
    2. TCP是雙工協議,雙方可以同時通訊,所以傳送方接收方各自維護一個傳送窗和接收窗。
      • 傳送窗:用來限制傳送方可以傳送的資料大小,其中傳送視窗的大小由接收端返回的TCP報文段中視窗欄位來控制,接收方透過此欄位告知傳送方自己的緩衝(受系統、硬體等限制)大小。
      • 接收窗:用來標記可以接收的資料大小。
    3. TCP是流資料,傳送出去的資料流可以被分為以下四部分:已傳送且被確認部分 | 已傳送未被確認部分 | 未傳送但可傳送部分 | 不可傳送部分,其中傳送窗 = 已傳送未確認部分 + 未發但可傳送部分。接收到的資料流可分為:已接收 | 未接收但準備接收 | 未接收不準備接收。接收窗 = 未接收但準備接收部分。
    4. 傳送窗內資料只有當接收到接收端某段傳送資料的ACK響應時才移動傳送窗,左邊緣緊貼剛被確認的資料。接收窗也只有接收到資料且最左側連續時才移動接收視窗。
  15. TCP擁塞控制

    擁塞控制目的是防止資料過多注入到網路中導致網路資源(路由器、交換機等)過載。因為擁塞控制涉及網路鏈路全域性,所以屬於全域性控制。控制擁塞使用擁塞視窗。

    擁塞控制主要是四個演演算法:1)慢啟動,2)擁塞避免,3)擁塞發生,4)快速恢復。

    慢熱啟動演演算法 – Slow Start

    所謂慢啟動,也就是TCP連線剛建立,一點一點地提速,試探一下網路的承受能力,以免直接擾亂了網路通道的秩序。

    慢啟動演演算法:

    1. 連線建好的開始先初始化擁塞視窗cwnd大小為1,表明可以傳一個MSS大小的資料。
    2. 每當收到一個ACK,cwnd大小加一,呈線性上升。
    3. 每當過了一個往返延遲時間RTT(Round-Trip Time),cwnd大小直接翻倍,乘以2,呈指數讓升。
    4. 還有一個ssthresh(slow start threshold),是一個上限,當cwnd >= ssthresh時,就會進入“擁塞避免演演算法”

    擁塞避免演演算法 – Congestion Avoidance

    如同前邊說的,當擁塞視窗大小cwnd大於等於慢啟動閾值ssthresh後,就進入擁塞避免演演算法。演演算法如下:

    1. 收到一個ACK,則cwnd = cwnd + 1 / cwnd
    2. 每當過了一個往返延遲時間RTT,cwnd大小加一。

    過了慢啟動閾值後,擁塞避免演演算法可以避免視窗增長過快導致視窗擁塞,而是緩慢的增加調整到網路的最佳值。

    擁塞發生狀態時的演演算法

    一般來說,TCP擁塞控制預設認為網路丟包是由於網路擁塞導致的,所以一般的TCP擁塞控制演演算法以丟包為網路進入擁塞狀態的訊號。對於丟包有兩種判定方式,一種是超時重傳RTO[Retransmission Timeout]超時,另一個是收到三個重複確認ACK。

    超時重傳是TCP協議保證資料可靠性的一個重要機制,其原理是在傳送一個資料以後就開啟一個計時器,在一定時間內如果沒有得到傳送資料包的ACK報文,那麼就重新傳送資料,直到傳送成功為止。

    但是如果傳送端接收到3個以上的重複ACK,TCP就意識到資料發生丟失,需要重傳。這個機制不需要等到重傳定時器超時,所以叫 做快速重傳,而快速重傳後沒有使用慢啟動演演算法,而是擁塞避免演演算法,所以這又叫做快速恢復演演算法。

    超時重傳RTO[Retransmission Timeout]超時,TCP會重傳資料包。TCP認為這種情況比較糟糕,反應也比較強烈:

    • 由於發生丟包,將慢啟動閾值ssthresh設定為當前cwnd的一半,即ssthresh = cwnd / 2.
    • cwnd重置為1
    • 進入慢啟動過程

    最為早期的TCP Tahoe演演算法就只使用上述處理辦法,但是由於一丟包就一切重來,導致cwnd又重置為1,十分不利於網路資料的穩定傳遞。

    所以,TCP Reno演演算法進行了最佳化。當收到三個重複確認ACK時,TCP開啟快速重傳Fast Retransmit演演算法,而不用等到RTO超時再進行重傳:

    • cwnd大小縮小為當前的一半
    • ssthresh設定為縮小後的cwnd大小
    • 然後進入快速恢復演演算法Fast Recovery。

    快速恢復演演算法 – Fast Recovery

    TCP Tahoe是早期的演演算法,所以沒有快速恢復演演算法,而Reno演演算法有。在進入快速恢復之前,cwnd和ssthresh已經被更改為原有cwnd的一半。快速恢復演演算法的邏輯如下:

    • cwnd = cwnd + 3 MSS,加3 MSS的原因是因為收到3個重複的ACK。
    • 重傳DACKs指定的資料包。
    • 如果再收到DACKs,那麼cwnd大小增加一。
    • 如果收到新的ACK,表明重傳的包成功了,那麼退出快速恢復演演算法。將cwnd設定為ssthresh,然後進入擁塞避免演演算法。
  16. 流量控制和擁塞控制的區別

    • 流量控制屬於通訊雙方協商;擁塞控制涉及通訊鏈路全域性。
    • 流量控制需要通訊雙方各維護一個傳送窗、一個接收窗,對任意一方,接收窗大小由自身決定,傳送窗大小由接收方響應的TCP報文段中視窗值確定;擁塞控制的擁塞視窗大小變化由試探性傳送一定資料量資料探查網路狀況後而自適應調整。
    • 實際最終傳送視窗 = min{流控傳送視窗,擁塞視窗}。
  17. TCP 協議如何保證可靠傳輸

    • 確認和重傳:接收方收到報文就會確認,傳送方傳送一段時間後沒有收到確認就會重傳。
    • 資料校驗:TCP報文頭有校驗和,用於校驗報文是否損壞。
    • 對失序資料包重排序:既然 TCP 報文段作為 IP 資料包來傳輸,而 IP 資料包的到達可能會失序,因此 TCP 報文段的到達也可能會失序。TCP 將對失序資料進行重新排序,才交給應用層;
    • 流量控制:當接收方來不及處理傳送方的資料,能透過滑動視窗,提示傳送方降低傳送的速率,防止包丟失。
    • 擁塞控制:當網路擁塞時,透過擁塞視窗,減少資料的傳送,防止包丟失。
    • 丟棄重複資料:對於重複資料,能夠丟棄重複資料;
    • 應答機制:當 TCP 收到發自 TCP 連線另一端的資料,它將傳送一個確認。這個確認不是立即傳送,通常將推遲幾分之一秒;
  18. 如何最佳化TCP

    從三個角度來闡述提升 TCP 的策略,分別是:

    • TCP 三次握手的效能提升;
    • TCP 四次揮手的效能提升;
    • TCP 資料傳輸的效能提升;

    TCP 三次握手的效能提升

    客戶端的最佳化

    當客戶端發起 SYN 包時,可以透過 tcp_syn_retries 控制其重傳的次數。

    服務端的最佳化

    當服務端 SYN 半連線佇列溢位後,會導致後續連線被丟棄,可以透過 netstat -s 觀察半連線佇列溢位的情況,如果 SYN 半連線佇列溢位情況比較嚴重,可以透過 tcp_max_syn_backlog、somaxconn、backlog 引數來調整 SYN 半連線佇列的大小。

    服務端回覆 SYN+ACK 的重傳次數由 tcp_synack_retries 引數控制。如果遭受 SYN 攻擊,應把 tcp_syncookies 引數設定為 1,表示僅在 SYN 佇列滿後開啟 syncookie 功能,可以保證正常的連線成功建立。

    服務端收到客戶端返回的 ACK,會把連線移入 accpet 佇列,等待進行呼叫 accpet() 函式取出連線。

    可以透過 ss -lnt 檢視服務端程式的 accept 佇列長度,如果 accept 佇列溢位,系統預設丟棄 ACK,如果可以把 tcp_abort_on_overflow 設定為 1 ,表示用 RST 通知客戶端連線建立失敗。

    如果 accpet 佇列溢位嚴重,可以透過 listen 函式的 backlog 引數和 somaxconn 系統引數提高佇列大小,accept 佇列長度取決於 min(backlog, somaxconn)。

    繞過三次握手

    TCP Fast Open 功能可以繞過三次握手,使得 HTTP 請求減少了 1 個 RTT 的時間,Linux 下可以透過 tcp_fastopen 開啟該功能,同時必須保證服務端和客戶端同時支援。

    TCP 四次揮手的效能提升

    客戶端和服務端雙方都可以主動斷開連線,通常先關閉連線的一方稱為主動方,後關閉連線的一方稱為被動方。

    針對 TCP 四次揮手的最佳化,我們需要根據主動方和被動方四次揮手狀態變化來調整系統 TCP 核心引數。

    [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片儲存下來直接上傳(img-vIOGjqUw-1678081583394)(https://cdn.xiaolincoding.com/gh/xiaolincoder/ImageHost/計算機網路/TCP-引數/39.jpg)]

    主動方的最佳化

    主動發起 FIN 報文斷開連線的一方,如果遲遲沒收到對方的 ACK 回覆,則會重傳 FIN 報文,重傳的次數由 tcp_orphan_retries 引數決定。

    當主動方收到 ACK 報文後,連線就進入 FIN_WAIT2 狀態,根據關閉的方式不同,最佳化的方式也不同:

    • 如果這是 close 函式關閉的連線,那麼它就是孤兒連線。如果 tcp_fin_timeout 秒內沒有收到對方的 FIN 報文,連線就直接關閉。同時,為了應對孤兒連線佔用太多的資源,tcp_max_orphans 定義了最大孤兒連線的數量,超過時連線就會直接釋放。
    • 反之是 shutdown 函式關閉的連線,則不受此引數限制;

    當主動方接收到 FIN 報文,並返回 ACK 後,主動方的連線進入 TIME_WAIT 狀態。這一狀態會持續 1 分鐘,為了防止 TIME_WAIT 狀態佔用太多的資源,tcp_max_tw_buckets 定義了最大數量,超過時連線也會直接釋放。

    當 TIME_WAIT 狀態過多時,還可以透過設定 tcp_tw_reusetcp_timestamps 為 1 ,將 TIME_WAIT 狀態的埠複用於作為客戶端的新連線,注意該引數只適用於客戶端。

    被動方的最佳化

    被動關閉的連線方應對非常簡單,它在回覆 ACK 後就進入了 CLOSE_WAIT 狀態,等待程式呼叫 close 函式關閉連線。因此,出現大量 CLOSE_WAIT 狀態的連線時,應當從應用程式中找問題。

    當被動方傳送 FIN 報文後,連線就進入 LAST_ACK 狀態,在未等到 ACK 時,會在 tcp_orphan_retries 引數的控制下重發 FIN 報文。

    TCP 資料傳輸的效能提升

    [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片儲存下來直接上傳(img-yvueg1Zy-1678081583395)(https://cdn.xiaolincoding.com/gh/xiaolincoder/ImageHost/計算機網路/TCP-引數/49.jpg)]

    TCP 可靠性是透過 ACK 確認報文實現的,又依賴滑動視窗提升了傳送速度也兼顧了接收方的處理能力。

    可是,預設的滑動視窗最大值只有 64 KB,不滿足當今的高速網路的要求,要想提升傳送速度必須提升滑動視窗的上限,在 Linux 下是透過設定 tcp_window_scaling 為 1 做到的,此時最大值可高達 1GB。

    滑動視窗定義了網路中飛行報文的最大位元組數,當它超過頻寬時延積時,網路過載,就會發生丟包。而當它小於頻寬時延積時,就無法充分利用網路頻寬。因此,滑動視窗的設定,必須參考頻寬時延積。

    核心緩衝區決定了滑動視窗的上限,緩衝區可分為:傳送緩衝區 tcp_wmem 和接收緩衝區 tcp_rmem。

    Linux 會對緩衝區動態調節,我們應該把緩衝區的上限設定為頻寬時延積。傳送緩衝區的調節功能是自動開啟的,而接收緩衝區需要把 tcp_moderate_rcvbuf 設定為 1 來開啟。其中,調節的依據是 TCP 記憶體範圍 tcp_mem。

    但需要注意的是,如果程式中的 socket 設定 SO_SNDBUF 和 SO_RCVBUF,則會關閉緩衝區的動態整功能,所以不建議在程式設定它倆,而是交給核心自動調整比較好。

  19. UDP協議

    提供無連線的,盡最大努力的資料傳輸服務(不保證資料傳輸的可靠性)。

    特點

    (1)UDP是無連線的傳輸層協議;

    (2)UDP使用盡最大努力交付,不保證可靠交付;

    (3)UDP是面向報文的,對應用層交下來的報文,不合並,不拆分,保留原報文的邊界;

    (4)UDP沒有擁塞控制,因此即使網路出現擁塞也不會降低傳送速率;

    (5)UDP支援一對一 一對多 多對多的互動通訊;

    (6)UDP的首部開銷小,只有8位元組.

  20. UDP 如何實現可靠傳輸

    UDP不屬於連線協議,具有資源消耗少,處理速度快的優點,所以通常音訊,影片和普通資料在傳送時,使用UDP較多,因為即使丟失少量的包,也不會對接受結果產生較大的影響。

    傳輸層無法保證資料的可靠傳輸,只能透過應用層來實現了。實現的方式可以參照tcp可靠性傳輸的方式,只是實現不在傳輸層,實現轉移到了應用層。

    最簡單的方式是在應用層模仿傳輸層TCP的可靠性傳輸。下面不考慮擁塞處理,可靠UDP的簡單設計。

    • 1、新增seq/ack機制,確保資料傳送到對端
    • 2、新增傳送和接收緩衝區,主要是使用者超時重傳。
    • 3、新增超時重傳機制。

    詳細說明:送端傳送資料時,生成一個隨機seq=x,然後每一片按照資料大小分配seq。資料到達接收端後接收端放入快取,併傳送一個ack=x的包,表示對方已經收到了資料。傳送端收到了ack包後,刪除緩衝區對應的資料。時間到後,定時任務檢查是否需要重傳資料。

    目前有如下開源程式利用udp實現了可靠的資料傳輸。分別為*RUDP、RTP、UDT*

  21. TCP和UDP的區別

    (1)TCP是可靠傳輸,UDP是不可靠傳輸;

    (2)TCP面向連線,UDP無連線;

    (3)TCP傳輸資料有序,UDP不保證資料的有序性;

    (4)TCP不儲存資料邊界,UDP保留資料邊界;

    (5)TCP傳輸速度相對UDP較慢;

    (6)TCP有流量控制和擁塞控制,UDP沒有;

    (7)TCP是重量級協議,UDP是輕量級協議;

    (8)TCP首部較長20位元組,UDP首部較短8位元組;

    TCP應用場景:

    效率要求相對低,但對準確性要求相對高的場景。因為傳輸中需要對資料確認、重發、排序等操作,相比之下效率沒有UDP高。舉幾個例子:檔案傳輸(準確高要求高、但是速度可以相對慢)、接受郵件、遠端登入。

    UDP應用場景:

    效率要求相對高,對準確性要求相對低的場景。舉幾個例子:QQ聊天、線上影片、網路語音電話(即時通訊,速度要求高,但是出現偶爾斷續不是太大問題,並且此處完全不可以使用重發機制)、廣播通訊(廣播、多播)

    基於TCP和UDP的常用協議

    HTTP、HTTPS、FTP、TELNET、SMTP(簡單郵件傳輸協議)協議基於可靠的TCP協議。DNS、DHCP、TFTP、SNMP(簡單網路管理協議)、RIP基於不可靠的UDP協議

  22. TCP黏包和拆包

    TCP黏包

    TCP粘包是指傳送方傳送的若干包資料到接收方接收時粘成一包,從接收緩衝區看,後一包資料的頭緊接著前一包資料的尾。

    • 由TCP連線複用造成的粘包問題。
    • 因為TCP預設會使用Nagle演演算法,此演演算法會導致粘包問題。
      • 只有上一個分組得到確認,才會傳送下一個分組;
      • 收集多個小分組,在一個確認到來時一起傳送。
    • 資料包過大造成的粘包問題。
    • 流量控制,擁塞控制也可能導致粘包。
    • 接收方不及時接收緩衝區的包,造成多個包接收

    解決

    1. Nagle演演算法問題導致的,需要結合應用場景適當關閉該演演算法
    2. 尾部標記序列。透過特殊識別符號表示資料包的邊界,例如\n\r,\t,或者一些隱藏字元。
    3. 頭部標記分步接收。在TCP報文的頭部加上表示資料長度。
    4. 應用層傳送資料時定長傳送。
    5. 特殊字元控制;
  23. URI和 URL之間的區別

    URL,即統一資源定位符 (Uniform Resource Locator ),URL 其實就是我們平時上網時輸入的網址,它標識一個網際網路資源,並指定對其進行操作或獲取該資源的方法。例如 https://leetcode-cn.com/problemset/all/ 這個 URL,標識一個特定資源並表示該資源的某種形式是可以透過 HTTP 協議從相應位置獲得。

    而 URI 則是統一資源識別符號,URL 是 URI 的一個子集,兩者都定義了資源是什麼,而 URL 還定義瞭如何能訪問到該資源。URI 是一種語義上的抽象概念,可以是絕對的,也可以是相對的,而URL則必須提供足夠的資訊來定位,是絕對的。簡單地說,只要能唯一標識資源的就是 URI,在 URI 的基礎上給出其資源的訪問方式的就是 URL。

相關文章