1. 程式人生 > 其它 >第二章 用電訊號傳輸TCP/IP資料---協議棧和網絡卡

第二章 用電訊號傳輸TCP/IP資料---協議棧和網絡卡

2.1 建立套接字

  • 像瀏覽器、 郵件等一般的應用程式都是使用 TCP 收發資料的, 而像 DNS 查詢等收發較短的控制資料的時候則使用 UDP。

    • IP 協議控制網路包收發操作的部分

    • ICMP 用於告知網路包傳送過程中產生的錯誤以及各種控制訊息

    • ARP 用於根據 IP 地址查詢相應的乙太網 MAC 地址

    • IP 下面的網絡卡驅動程式負責控制網絡卡硬體, 而最下面的網絡卡則負責完成實際的收發操作, 也就是對網線中的訊號執行傳送和接收的操作

  • 在協議棧內部有一塊用於存放控制資訊的記憶體空間, 這裡記錄了用於控制通訊操作的控制資訊, 例如通訊物件的 IP 地址、 埠號、 通訊操作的進行狀態等

  • 協議棧是根據套接字中記錄的控制資訊來工作的

  • 呼叫socket()時的操作

    • 建立套接字時,首先分配一個套接字所需的記憶體空間,然後向其中寫入初始狀態。

    • 然後將這個套接字的描述符告知應用程式 ,描述符用來區分協議棧中的多個套接字的號碼牌

2.2 連線伺服器

  • 連線是什麼意思?

    • 當套接字建立完成時,伺服器上的協議棧和客戶端一樣, 只建立套接字是不知道應該和誰進行通訊。

    • 客戶端需要把想要連線的伺服器的 IP 地址和埠號等資訊告知協議棧 ,這是連線的目的之一

    • 客戶端向伺服器傳達開始通訊的請求,也是連線操作的目的之一

    • 連線實際上是通訊雙方交換控制資訊, 在套接字中記錄這些必要資訊並準備資料收發的一連串操作

    • 當執行資料收發操作時, 我們還需要一塊用來臨時存放要收發的資料的記憶體空間, 這塊記憶體空間稱為緩衝區, 它也是在連線操作的過程中分配的 。分配緩衝區

  • 通訊操作中使用的控制資訊分為兩類

    • 頭部中記錄的資訊:記錄和交換控制資訊的

    • 套接字(協議棧中的記憶體空間)中記錄的資訊:控制協議棧操作的。包括:應用程式傳遞來的資訊、從通訊物件接收到的資訊、收發資料操作的執行狀態等資訊

  • 連線操作的實際過程

    • connect( < 描述符 >, < 伺服器 IP 地址和埠號 >, …)

    • 會把伺服器的 IP 地址和埠號傳遞給協議棧中的 TCP 模組 ,TCP 模組會 和伺服器的TCP模組交換控制資訊,交換包括以下幾個步驟

      • 客戶端先建立一個包含表示開始資料收發操作的控制資訊的頭部 ,然後將頭部中的控制位的 SYN 位元設定為 1, 大家可以認為它表示連線 ,還需要設定適當的序號和視窗大小

      • 當 TCP 頭部建立好之後, 接下來 TCP 模組會將資訊傳遞給 IP 模組並委託它進行傳送 到伺服器

      • 伺服器上的 IP 模組會將接收到的資料傳遞給 TCP 模組

      • 伺服器的 TCP 模組根據 TCP 頭部中的資訊找到埠號對應的套接字

      • 當找到對應的套接字之後, 套接字中會寫入相應的資訊, 並將狀態改為正在連線

      • 上述操作完成後, 伺服器的 TCP 模組會返回響應, 這個過程和客戶端一樣 。在返回響應時還需要將 ACK 控制位設為1,雙方在通訊時必須相互確認網路包是否已經送達

      • 客戶端會檢查TCP 頭部的資訊確認連線伺服器的操作是否成功 ,如果 SYN 為 1 則表 示連線成功, 這時會向套接字中寫入伺服器的 IP 地址、 埠號等資訊, 同時還會將狀態改為連線完畢

      • 最後客戶端也需要將 ACK 位元設定為 1 併發回伺服器, 告訴伺服器剛才的響應包已經收到

      • 經過以上步驟,套接字就已經進入隨時可以收發資料的狀態了

2.3 收發資料

  • 資料收發操作是從應用程式呼叫 write 將要傳送的資料交給協議棧 ,協議棧並不是一收到資料就馬上傳送出去, 而是會將資料存放在內部的傳送緩衝區中 ,為什麼放到緩衝區中到一定長度再發送?

    • 應用程式傳送給協議棧的資料長度是由應用程式決定的,也可能幾字節或者一行資料,如果一收到資料就馬上傳送出去, 就可能會發送大量的小包, 導致網路效率下降

  • 積累到多少位元組傳送?

    • MTU 表示一個網路包的最大長度 ,乙太網中是1500位元組,去除頭部後是MSS(一個網路包所能容納的 TCP 資料的最大長度 )

    • 第二個要素是時間:當應用程式傳送資料的頻率不高的時候, 如果每次都等到長度接近 MSS 時再發送, 可能會因為等待時間太長而造成發 送延遲 ,為此, 協議棧的內部有一個計時器, 當經過一定時間之後,就會把網路包傳送出去

    • 這兩個要素之間相互矛盾,應用程式在傳送資料時可以指定一些選項

  • 傳送緩衝區中的資料超過 MSS 的長度 就要以MSS為單位進行拆分,分成不同的網路包傳送出去

  • 實際傳送過程中,序號並不是從 1 開始的, 而是需要用隨機數計算出一個初始值 ,為了防攻擊

  • 傳送的實際過程

    • 客戶端計算出序號初始值,併發送給伺服器

    • 伺服器會通過這個初始值計算出 ACK 號並返回給客戶端 ,同時伺服器也要計算出往客戶端通訊這一側的序號初始值,並返回給客戶端

    • 客戶端需要根據伺服器發來的序列號計算出ACK返給伺服器

  • 通過“序號”和“ACK 號”可以確認接收方是否收到了網路包。

  • 根據網路包平均往返時間調整 ACK 號等待時間

    • TCP 採用了動態調整等待時間的方法, 這個等待時間是根據 ACK 號返回所需的時間來判斷的。 具體來說, TCP 會在傳送資料的過程中持續測量 ACK 號的返回時間, 如果 ACK 號返回變慢, 則相應延長等待時間; 相對地, 如果 ACK 號馬上就能返回, 則相應縮短等待時間 。

  • 每傳送一個包就等待一個 ACK 號 效率是很低的。為此採用滑動視窗方式來管理資料傳送和 ACK 號的操作:就是在傳送一個包之後, 不等待 ACK 號返回, 而是直接傳送後續的一系列包

  • 採用滑動視窗這種方式,可能會出現傳送包的頻率超過接收方處理能力的情況

    • 如果資料到達的速率比處理這些資料並傳遞給應用程式的速率還要快, 那麼接收緩衝區中的資料就會越堆越多, 最後就會溢位,緩衝區溢位之後, 後面的資料就進不來了, 因此接收方就收不到後面的包了,接收方需要告訴傳送方自己最多能接收多少資料,然後傳送方根據這個值對資料傳送操作進行控制, 這就是滑動視窗方式的基本思路

    • 能夠接收的最大資料量稱為視窗大小 ,一般和接收方的緩衝區大小一樣

  • 什麼時候需要更新視窗大小呢?

    • 是接收方從緩衝區中取出資料傳遞給應用程式的時候。 這個操作是接收方應用程式發出請求時才會進行的, 而傳送方不知道什麼時候會進行這樣的操作, 因此當接收方將資料傳遞給應用程式, 導致接收緩衝區剩餘容量增加時, 就需要告知傳送方, 這就是更新視窗大小的時機

  • 什麼時候傳送ACK號?

    • 當接收方收到資料之後就傳送ACK號

  • 接收方在傳送 ACK 號和視窗更新時, 並不會馬上把包傳送出去, 而是會等待一段時間, 在這個過程中很有可能會出現其他的通知操作,這樣就可以把兩種通知合併在一個包裡面傳送了

  • 接收HTTP響應訊息

    • 會呼叫read函式進行接收,協議棧嘗試從接收緩衝區中取出資料並傳遞給應用程式, 但這個時候請求訊息剛剛傳送出去, 響應訊息可能還沒返回。 響應訊息的返回還需要等待一段時間, 因此這時接收緩衝區中並沒有資料 ,這時協議棧會從接收緩衝區中取出資料並傳遞給應用程式的工作暫時掛起 ,等伺服器返回的響應訊息到達之後再繼續執行接收操作

  • 接收資料的過程總結

    • 首先, 協議棧會檢查收到的資料塊和 TCP 頭部的內容, 判斷是否有資料丟失, 如果沒有問題則返回 ACK 號。 然後,協議棧將資料塊暫存到接收緩衝區中, 並將資料塊按順序連線起來還原出原始的資料, 最後將資料交給應用程式。 具體來說, 協議棧會將接收到的資料複製到應用程式指定的記憶體地址中, 然後將控制流程交回應用程式。將資料交給應用程式之後, 協議棧還需要找到合適的時機向傳送方傳送視窗更新

2.4 從伺服器斷開並刪除套接字

  • 收發資料結束的時間點應該是應用程式判斷所有資料都已經發送完畢的時候,協議棧在設計上允許任何一方先發起斷開過程,以伺服器斷開連線過程為例:

    • 伺服器一方的應用程式會呼叫 Socket 庫的 close 程式

    • 然後, 伺服器的協議棧會生成包含斷開資訊的 TCP 頭部, 具體來說就是將控制位中的 FIN 位元設為 1

    • 然後協議棧會委託 IP 模組向客戶端傳送資料 ,同時伺服器的套接字中也會記錄下斷開操作的相關資訊

    • 當客戶端收到伺服器發來的 FIN 為 1 的 TCP 頭部時,客戶端的協議棧會將自己的套接字標記為進入斷開操作狀態

    • 告知伺服器已收到 FIN 為 1 的包, 客戶端會向伺服器返回一個 ACK 號

    • 這些操作完成後, 協議棧就可以等待應用程式來取資料了

    • 當呼叫read收到全部的資料後,客戶端應用程式會呼叫 close 來結束資料收發操作,這時客戶端的協議棧也會和伺服器一樣, 生成一個 FIN 位元為 1 的 TCP 包, 然後委託 IP 模組傳送給伺服器 ,一段時間之後, 伺服器就會返回ACK 號,至此客戶端和伺服器的通訊就全部結束了

  • 當通訊結束後,過一段時間就會刪除套接字,過一段時間的目的是為了防止誤操作

    • 如果最後客戶端返回的 ACK 號丟失了,伺服器沒有接收到 ACK 號, 可能會重發一次 FIN,如果這時客戶端的套接字已經刪除了,套接字對應的埠號就會被釋放出來 ,如果別的應用程式要建立套接字, 新套接字碰巧又被分配了同一個埠號,這樣就會誤刪新的套接字

2.5 IP 與乙太網的包收發操作

  • 包是由頭部和資料兩部分構成的 ,頭部包含目的地址等控制資訊,包發往目的地址的過程

    • 傳送方的網路裝置會負責建立包, 建立包的過程就是生成含有正確控制資訊的頭部, 然後再附加上要傳送的資料

    • 包會發往最近的網路轉發裝置

    • 當到達最近的轉發裝置之後, 轉發裝置會根據頭部中的資訊判斷接下來應該發往哪裡

    • 經過多個轉發裝置的接力之後, 包最終就會到達接收方的網路裝置

  • 集線器是按照乙太網規則傳輸包的裝置, 而路由器是按照 IP規則傳輸包的裝置 。

    • 路由器:根據目標地址找到下一個路由

    • 集線器:在子網中將一個數據包傳給下一個路由

  • 傳送方要把訪問的伺服器的 IP 地址寫入 IP 頭部中 ,IP 協議就可以根據這一地址查詢包的傳輸方向, 從而找 到下一個路由器的位置 ,接下來, IP 協議會委託乙太網協議將包傳輸過去 ,這時, IP 協議會查詢下一個路由器的乙太網地址( MAC 地址), 並將這個地址寫入 MAC 頭部中。 這樣一來, 乙太網協議就知道要將這個包發到哪一個路由器上了。

  • 包收發操作的起點是 TCP 模組委託 IP 模組傳送包的操作 ,這個委託的過程就是 TCP 模組在資料塊的前面加上 TCP頭部, 然後整個傳遞給 IP 模組, 這部分就是網路包的內容

  • 收到委託後, IP 模組會將包的內容當作一整塊資料, 在前面加上包含控制資訊的頭部,IP 模組會新增 IP 頭部和 MAC 頭部這兩種頭部

    • IP 頭部中包含 IP 協議規定的、 根據 IP 地址將包發往目的地所需的控制資訊 ,最重要的資訊是IP地址,是TCP模組告知的。ip頭部還需要標明發送方的 IP 地址 ,如果只有一塊網絡卡,傳送方的地址就是本機地址,如果有多塊網絡卡怎麼判斷呢?

      • 通過 route print 命令顯示路由表

      • 把目的地 IP 地址與路由表左側的 Network Destination 欄進行比較 ,IP 模組根據路由表 Gateway 欄的內容判斷應該把包傳送給誰。

    • MAC 頭部包含通過乙太網的區域網將包傳輸至最近的路由器 所需的控制資訊

      • MAC 頭部的開頭是接收方和傳送方的 MAC 地址,地址為 48 位元

      • 第 3 個以太型別欄位和 IP 頭部中的協議號類似,表示後面內容的型別。 乙太網包的內容可以是 IP、 ARP等協議的包

      • 通過 ARP 查詢接收方的 MAC 地址,把查詢到的結果放在ARP 快取的記憶體空間 。為了保證值都是有效的在經過一段時間後把ARP 快取的記憶體空間 中的所有值刪除

  • 無論要收發的包是控制包還是資料包,IP 對各種型別的包的收發操作都是相同的

  • 乙太網在判斷網路包目的地時和 TCP/IP 的方式不同,需要根據MAC地址判斷

  • 乙太網是一種為多臺計算機能夠彼此自由和廉價地相互通訊而設計的通訊技術

  • IP 生成的網路包只是存放在記憶體中的一串數字資訊, 沒有辦法直接傳送給對方。 因此, 我們需要將數字資訊轉換為電或光訊號, 才能在網線上傳輸 ,負責執行這一操作的就是網絡卡

  • 網絡卡的初始化過程?

    • 開啟計算機啟動作業系統的時候, 網絡卡驅動程式會對硬體進行初始化操作, 然後硬體才進入可以使用的狀態 。操作包括硬體錯誤檢查、 初始設定等步驟 ,還需要在控制乙太網收發操作的MAC模組中設定MAC地址

    • 網絡卡的 ROM 中儲存著全世界唯一的 MAC 地址 ,將這個值讀出之後就可以對 MAC 模組進行設定 MAC 模組就知道自己對應的 MAC 地址了

  • 網絡卡是如何將包轉換成電訊號併發送到網線中的 ?

    • 網絡卡驅動從 IP 模組獲取包之後, 會將其複製到網絡卡內的緩衝區中, 然後向MAC 模組傳送傳送包的命令。 接下來就輪到 MAC 模組進行工作了。

    • MAC 模組會將包從緩衝區中取出, 並在開頭加上報頭和起始幀分界符, 在末尾加上用於檢測錯誤的幀校驗序列

    • 報頭是一串像 10101010…這樣 1 和 0 交替出現的位元序列, 長度為 56位元, 它的作用是確定包的讀取時機

  • 加上報頭、 起始幀分界符和 FCS 之後, 我們就可以將包通過網線傳送出去了, 傳送訊號的操作分為兩種, 一種是使用集線器的半雙工模式, 另一種是使用交換機的全雙工 模式。

  • 網絡卡的 MAC 模組生成通用訊號,然後由 PHY(MAU)模組轉換成可在網線中傳輸的格式,並通過網線傳送出去

  • 接收包的過程

    • PHY( MAU) 模 塊 先 開 始 工 作, 然 後 再 輪 到 MAC 模 塊 ,( MAU) 模組會將訊號轉換成通用格式併發送給 MAC 模組, MAC 模組再從頭開始將訊號轉換為數字資訊, 並存放到緩衝區中。 當到達訊號的末尾時, 還需要檢查 FCS。

    • 如果 FCS 校驗沒有問題, 接下來就要看一下 MAC 頭部中接收方MAC 地址與網絡卡在初始化時分配給自己的 MAC 地址是否一致, 以判斷這個包是不是發給自己的 ,如果地址一致,將包放入緩衝區中 ,MAC 模組的工作就完成了, 接下來網絡卡會通知計算機收到了一個包。 通知計算機的操作會使用一個叫作中斷的機制

    • 網絡卡驅動被中斷處理程式呼叫後, 會從網絡卡的緩衝區中取出收到的包,並通過 MAC 頭部中的以太型別欄位判斷協議的型別

    • 假如乙太網型別是0080( 十六進位制),網絡卡驅動會將其交給 TCP/IP 協議棧來進行處理

    • 接下來就輪到 IP 模組先開始工作了, 第一步是檢查 IP 頭部, 確認格式是否正確。 如果格式沒有問題, 下一步就是檢視接收方 IP 地址,如果接收方IP地址和自己的地址一致就接受這個包,否則不對包進行轉發,發生錯誤時,IP 模組會通過 ICMP 訊息將錯誤告知傳送方

    • 這些包是經過分片的,IP 模組會將它們還原成原始的包 (分片重組)

    • 到這裡, IP 模組的工作就結束了, 接下來包會被交給 TCP 模組。 TCP模組會根據 IP 頭部中的接收方和傳送方 IP 地址, 以及 TCP 頭部中的接收方和傳送方埠號來查詢對應的套接字

    • 找到對應的套接字之後, 就可以根據套接字中記錄的通訊狀態, 執行相應的操作了

2.6 UDP 協議的收發操作

  • 不需要重發的資料用 UDP 傳送更高效 。如果傳送的資料很短, 用一個包就能裝得下,就可用UDP傳送

  • 像 DNS 查詢等交換控制資訊的操作基本上都可以在一個包的大小範圍內解決, 這種場景中就可以用 UDP 來代替TCP

  • 傳送視訊、音視訊一般用UDP來發送