目錄
1. UDP 協議
1.1 協議特點
1.2 協議報文格式
1.2.1 UDP 長度?
1.2.2 校驗和
1. UDP 協議
在進行網絡編程時, 我們已經對 UDP 協議進行了簡單了解. 并且應用層的很多操作, 需要調用傳輸層的提供的接口, 基于 socket api 來進行完成的.
1.1 協議特點
UDP 協議具有以下特點:
- 面向數據報
- 不可靠傳輸
- 全雙工
- 無連接
在進行網絡編程使用 UDP socket api 進行數據傳輸時, 我們就對其中的一些特點有了一些感受:
面向數據報體現于: 每發送(send)或接收(receive)一次消息, 都是一個完整的 udp 報文.
全雙工體現在: 不論是客戶端還是服務器, 都可以進行 send 和 receive 操作.
無連接體現在: UDP 報文直接發送, 對端就可以接收, 并沒有像 TCP 那樣 accept 的過程.
不可靠傳輸, 是指消息發出后, 就不管了(不管數據是否成功發送到對端).?這一點并沒有在編程時具體體現, 接下來我們通過 udp 協議的報文格式來了解這一特點.
1.2 協議報文格式
UDP 數據報由兩個部分組成:
- UDP 報頭
- 載荷(完整的應用層數據包)
其中, 載荷就是完整的應用層數據報.
報頭, 大小為 64 個 bit 位, 8 個字節, 由以下四個部分組成:
- 源端口號
- 目的端口號
- 報文長度
- 校驗和
其中, 每個部分都占了 2 個字節.
至于源端口號和目的端口號的作用, 這里就不再贅述了, 主要聊一聊其中的 報文長度 和 檢驗和.
1.2.1 UDP 長度?
UDP 報文格式中的長度這一部分, 表示的是整個 UDP 數據報的長度, 即報頭 + 載荷的長度.?
由于大小為 2 字節, 也就是 16 個 bit 位, 所以 UDP 數據包長度的范圍為 0~2^16-1, 也就是 0~65535, 所以一個 UDP 數據報最大只能為?65535 個字節, 也就是?64kb.
由于報頭部分的大小是固定的, 8 字節, 這相對于 64kb(65535 字節) 來說是可以忽略不計的.
所以, 當我們面試表述 UDP 報文大小的上限時, 既可以說 64kb 是整個 UDP 數據包的上限, 也可以說是 UDP 攜帶的載荷的上限.
?64 kb, 在設計 UDP 的那個年代, 確實是一個充裕的大小, 但是放到 2024 年的今天, 就是一個非常小的數字了, 隨隨便便一張照片就可能是幾個 MB.
所以要發送數據的大小超出 UDP 數據包可以承載的大小的情況是經常發生的, 而當發送的大小一旦超過了 64kb, UDP 數據包就會被直接截斷, 對方拿到的數據就會出錯, 那么如何解決這個問題呢?? 有兩個方案可以選擇:
- 方案一: 在應用層代碼上進行拆包操作, 把一個大的應用層數據報拆成很多小的數據包, 再使用多個 UDP 數據包進行傳輸.
- 方案二: 使用 TCP 協議, 使用 TCP 數據包進行傳輸(TCP 沒有長度的限制).
方案一, 是一個工作量比較大的方法, 需要對代碼進行大量的修改, 寫大量的邏輯來實現分包組包的工作, 并且一不小心可能就寫出了隱藏 bug, 效率太低.
所以, 在工作中, 我們會優先選擇簡單且不易出錯的方案來解決問題, 即采用方案二, 使用 TCP 來解決 UDP 數據包大小限制的問題.
可能大家心中有一個疑問: 為啥不直接修改 UDP 的報文格式, 直接把 UDP 本身改的大一點呢??
其實, 要修改 UDP 很容易, 但是難就難在, UDP 已經內置在各種的操作系統中, 一旦發生變動, 就會造成很大的影響, 比如通信雙方, 一方進行了修改, 另一方沒有進行修改, 那么 UDP 數據包就會傳輸失敗, 導致不能使用 UDP 進行通信. 并且, 修改也會牽扯到系統兼容性的問題, 所以, 通信雙方誰先改, 誰可能就會出現問題.
所以 UDP 可以說是積重難返了, 目前也只能這樣子~~
1.2.2 校驗和
UDP 報文中的校驗和, 作用是為了驗證傳輸的數據是否發生修改.
注意, 這里的校驗和與 HTTPS 中數字簽名的校驗和不同, HTTPS 數字簽名的校驗和是為了反正數據被黑客篡改(防人), 但是這里 UDP 的校驗和, 與安全性無關, 而是防止傳輸過程中出現"比特翻轉".
比特翻轉, 就是在傳輸的過程中, 由于外界的影響, 導致數據中的某些 bit 位0變1, 1變0.
(數據都是以光電信號或者電磁波的形式進行傳輸的, 很容易收到外界的干擾)
驗證的過程如下:
- 發送之前, 會把整個數據報中的數據代入, 計算得出一個校驗和, 并將數據和校驗和一同發給對端.
- 對端收到數據后, 根據收到的數據, 再次計算校驗和, 將兩個校驗和進行對比, 如果校驗和不一致, 說明有數據發生了比特翻轉, 直接丟棄.
這里 UDP 采用的 CRC(循環冗余校驗) 的方式來計算校驗和:
- CRC: 把 UDP 報文中的每個字節(除了校驗和位置外), 都當做整數, 進行累加, 即使溢出也沒關系, 繼續加, 最終得到的數據就是 CRC 校驗和.
所以, 如果在傳輸過程中, 有 bit 位發生了翻轉, 那么兩次計算得到的校驗和也會不同.
我們可以認為, 如果兩個數據是相同的數據, 那么計算得到的校驗和一定是相同的.
但是, 當兩次計算的校驗和相同時, 兩個數據不一定是相同的.
因為, 這其中可能存在變數, 例如: CRC 是累加的方式計算的校驗和, 如果第一個字節發生的翻轉, 使得值變小了, 而第二個字節發生的偏轉又使值變大了, 而恰恰這兩次偏轉各自的差值又相互抵消, 那得到的校驗和依然是相同的.
雖然, 可能出現上述情況, 但是這種情況發生的概率是非常小的(發生翻轉的概率本來就小, 再加上兩次偏轉的影響又相互抵消, 概率就小之又小了), 所以在實際開發中, 我們可以忽略這種情況的存在.
綜上, 我們可以通過 UDP 報文中的校驗和這一部分, 來確定數據在傳輸時, 是否發生了修改~?
END