1.TCP和UDP
2.TCP為什么慢于UDP
3.可靠UDP
1.TCP和UDP
1).通過打電話的方式說明TCP和UDPa.TCP(傳輸控制協議), 就像打電話- 需要先撥號, 接通, 問候(建立連接)- 你一句, 我一句, 對方沒有聽清會要求你重復(確認與重傳)- 保證對話有條不紊, 內容準確無誤(可靠, 有序)- 如果信號不好, 你們會下意識地慢點說(擁塞控制)- 最后會禮貌道別(斷開連接)b.UDP(用戶數據報), 就像學校廣播站發公告- 拿起麥克風就直接說, 不管下面有沒有聽(無連接) - 只管自己念完, 不關心學生聽沒聽清, 記沒記住(無確認, 不可靠)- 念得飛快, 一口氣念完所有內容(高效, 速度塊)- 各個班級聽到的順序可能不同(無序)- 即使有學生喊"沒有聽清", 廣播站也不會重復(不重傳)
2).TCP(傳輸控制協議)a.連接性面向連接, 傳輸數據前必須通過三次握手建立一條邏輯連接通道; 傳輸結束后通過四次揮手斷開連接b.可靠性高可靠性, 確保數據無差錯, 不丟失, 不重復, 按次序到達c.流量控制有, 由接收方控制發送方的速率, 防止發送過快導致接收方緩沖區溢出d.擁塞控制有, 根據網絡狀況動態調整發送速率, 避免網絡癱瘓e.有序性有序, 對每個數據字節進行編號, 接收端會重新排序, 保證應用程序收到的數據和發送順序一致f.數據模式面向字節流, 將數據看作一連串無結構的字節流, 沒有邊界; 所以會出現黏包問題, 需要應用層自行解決g.首部開銷首部結構復雜, 包含序列號, 確認號, 窗口大小, 校驗等控制信息h.傳輸效率速度相對慢, 延遲較高; 因為需要建立連接, 確認, 重傳, 流量控制和擁塞控制, 帶來了額外的延遲i.雙工性在一條TCP連接上, 雙方可以同時進行數據的發送和接收j.應用場景要求數據絕對準確, 完整性大于速度的場景, 比如: 電子郵件(SMRTP, POP3, IMAP), 文件傳輸(FTP)
3).UDP(用戶數據報)a.連接性無連接, 無需建立和斷開連接, 想發數據就直接發b.可靠性盡最大努力交付, 不保證數據一定到達終點, 可能丟失, 亂序或重復c.流量控制無, 發送速率不受接收方控制, 可能因發送過快導致接收方丟包d.擁塞控制沒有擁塞控制, 即使網絡擁堵, 也以恒定速率發送數據, 可能會加劇網絡擁堵e.有序性每個數據報都是獨立的, 不保證先后順序, 接收端收到的是什么順序就是什么順序f.數據模式面向報文的, 發送和接收的都是完整的, 有邊界的數據; 應用層交付的數據包不會合并也不會拆分g.首部開銷首部非常簡單, 僅包含源/目標端口, 長度, 校驗等基本信息h.傳輸效率沒有復雜的控制機制, 傳輸效率高, 延遲低i.雙工性支持一對一, 一對多, 多對多j.應用場景要求傳輸速度和實時性, 速度大于完整性的場景; 比如: 音視頻直播, 語音通話等
2.TCP為什么慢于UDP
TCP慢于UDP, 是因為TCP為了保證可靠性而犧牲部分速度1).確認應答(ACK)和超時重傳- UDP, 發送方發送完數據就結束了, 不管對方是否收到, 就像仍紙團, 扔出去就不管了- TCP, 發送方每發送一個數據包, 都必須收到接收方的確認回復(ACK)后, 才會發送下一個; 如果一段時間內沒有收到ACK, 發送方就認為數據包丟了, 會重新發送由于TCP每次發送和等待ACK都需要等待時間(即RTT - 往返時間), 網絡延遲本身就高的環境下(如衛星鏈路), 這種一來一回的等待就會非常明顯; 重傳更是增加了額外的時間成本2).按序交付- UDP, 接收方收到什么就立刻上交什么, 不管順序; 后發的包可能先到- TCP, 必須保證接收方應用程序讀到的數據順序和發送方發出的順序完全一致; 如果中間某個數據包丟失或延遲了, 即使后面的數據包已經到達, 接收方也必須將它們緩存起來, 等待丟失的那個包重傳成功并組裝順序后, 才交給應用層由于TCP需要按序交付, 這造成了隊頭阻塞, 一個包的丟失或延遲就會拖累后面所有已到達但無序的數據無法及時處理3).流量控制- 目的, 防止發送方發送的過快, 導致接收方的緩沖區溢出- 機制, 主要通過TCP首部的窗口大小來實現, 接收方告訴發送方"我目前還能接收多少數據"; 發送方發送的數據量不能超過這個窗口- 帶來的延遲, 如果接收方處理速度慢(比如應用程序讀取數據慢), 窗口會變小, 設置為0; 發送方就必須暫停發送, 等待接收方騰出緩沖區并告知新的窗口大小; 這個等待就引入了延遲4).擁塞控制- 目的, 防止發送方發送的過快, 導致網絡中間設備過載, 它感知網絡的承載能力- 核心機制, 一套復雜的算法(慢啟動, 遇到擁塞等), 通過動態調整一個擁塞窗口的值來控制發送速率慢啟動: 連接剛建立時, 發送速率會從很低的值開始, 然后像指數增長一樣迅速增加, 直到遇到閾值或發現丟包(網絡擁塞的信號)遇到擁塞: 一旦檢測到丟包(超時), TCP會認為網絡堵了, 會劇烈地減小發送速率, 然后再開始緩慢增長- 帶來的延遲/速度變化, 擁塞控制使得TCP的速度不是穩定的, 而是像一個鋸齒波一樣上下波動, 它永遠在試探網絡的極限帶寬, 一旦碰壁后就后退; UDP一直以恒定的速率發送, 擠占其他連接帶寬, 直到把網絡塞滿
3.可靠UDP
游戲開發中的可靠UDP是有選擇地實現部分TCP的功能, 只會實現當前業務最需要的那部分; 必須實現的功能1).序列號a.判斷丟包, 沒有序列號, 根本無從知道包2和包3之間是不是丟了一個包b.判斷重復包, 網絡抖動可能讓我們收到兩個一樣的包, 序列號可以幫我們去重c.對于需要按順序執行的指令, 接收方可以依據序列號進行排序后提交給游戲邏輯處理注: 在接收方, 序列號用于判斷和排序, 不一定要像TCP那樣阻塞等待; 比如包3到了但包2沒到, 對于非關鍵數據可以直接處理包3, 對于關鍵指令則可以等待包2重傳后再按順序處理2).丟包檢測a.為什么實現UDP本身不告訴你數據是否到達, 如果槍擊指令的包丟了, 玩家會覺得自己開了空槍, 體驗極差; 所以你必須自己能檢測到哪個包可能丟了b.如何實現- 確認應答(ACK), 接收方收到包后, 會發送一個ACK消息回去, 告訴發送方法我收到了X號包- 否定確認(NACK), 接收方發現序列號不連續(比如收到了包1和包3, 沒有收到包2), 會主動發送一個NACK的消息, 請求發送方重傳包2- 超時計時器, 發送方為每個已發送的包啟動一個計時器, 如果在一定的時間內沒有收到對應的ACK, 就認為丟了, 觸發重傳3).重傳機制a.為什么必須檢測到丟包是為了補救, 重傳是保證關鍵數據可靠的最終手段b.關鍵: 選擇性重傳, 不是所有數據都值得重傳- 需要重傳的: 關鍵的指令, 比如玩家釋放技能- 不需要重傳的: 比如玩家的位置和朝向, 對于這種數據, 最新的數據永遠比舊數據更有價值4).擁塞控制(強烈建議實現)a.為什么如果我們的游戲不顧網絡擁堵情況瘋狂發送和重傳數據, 會拖垮整個局域網或路由器的性能, 最終所有人的連接質量下降b.我們不需要實現TCP那樣復雜的擁塞控制算法, 可以實現一個輕量級, 對游戲友好的版本- 監測往返時間(RTT)的變化, 如果RTT持續變大, 說明網絡可能擁堵了, 應適當降低發送速率- 監測丟包率, 丟包率上升也是網絡擁堵的標志