天天看點

網絡遊戲如何使用UDP提供可靠傳輸

  UDP本身不提供可靠傳輸,但是傳輸效率比TCP高。能提供可靠傳輸的UDP應該是UDP和TCP的某種折衷,這樣它才能提供可靠的,有效率的傳輸。

  是以我們得先了解TCP使如何提供可靠傳輸的,再看看TCP效率不高的原因是什麼,最後提出一種可靠的UDP傳輸方案。

TCP是如何提供可靠傳輸
  • 建立連接配接(标志位):通信前确認通信實體存在。
  • 序号機制(序号、确認号):確定了資料是按序、完整到達。
  • 資料校驗(校驗和):CRC校驗全部資料。
  • 逾時重傳(定時器):保證因鍊路故障未能到達資料能夠被多次重發。
  • 視窗機制(視窗):提供流量控制,避免過量發送。
  • 擁塞控制:同上。
TCP不用于網絡遊戲的原因
  • 首先,TCP是一個流式協定,是以你隻需寫資料到一個流,TCP會確定它們到達另一方。因為IP協定是建立在資料包上的,而TCP協定又是建立在IP協定上的,是以TCP必需将你的流式資料拆分成資料包。是以,一些内部的TCP代碼将你發送的資料放入消息隊列,當隊列中有足夠的資料,它才會發包給另一個機器。這就會有一個問題,如果你發送一個很小的資料包。TCP可能會決定它不會立即發送資料,直到緩沖區有足夠的資料組成一個合理大小的包。這樣用戶端的體驗就會很差。

      TCP有個選項,你可以用來修複它的這種行為,叫作“TCP_NODELAY”。這個選項通知TCP不用等到隊列中有足夠的資料,立即發送你寫入的任何資料。

  • 更關鍵的是TCP可靠性在于重發和重組。當一個資料包丢失後,就不得不停下來,等待這個資料包重傳。即使最近的資料達了,新的資料已經到達隊列了,你還是不能讀取它,直到你收到了丢掉的資料包。
如何用UDP實作可靠傳輸

  UDP的可靠傳輸實作分為兩部分“可靠性”和“避免擁堵”。

  • 可靠性:采用重發機制。
    • 類似TCP的ack機制。關于丢包檢查,可以采用一個近似TCP的ack機制,可以給每個資料包都添加一個sequence ID,然後發送端就依次發送資料包,接收端收到資料包後就可以根據sequence ID來判斷是否有丢包了。接收端需要發該sequenceID的ack給發送端,發送端才會知道這個包是否已經送達。與TCP不同的是如果資料包n丢失了我們也從不暫停重新發送它,而是把它留給應用程式來編寫一個包含丢失資料的新的資料包,必要的話,這個包還會用一個新的序列号發送。ack本身也有可能丢包。
    • 可以這樣,發送一個sequence ID的ack時,附加一個32bit的位序列,表示目前sequence ID之前的32個連續順位的資料包是否已經送達。其實就是備援的發送連續32個包的送達狀态,如果bit為0說明這個包還沒到,如果為1,說明已經收到了。這樣一來,除非連續丢包30多次,ack是一定會送到的,這種幾率已經非常小了。
    • 相應的,在發送端設定一個逾時機制,這個時間差不多比連續發30個ack的時間長一點,如果發送一個包後開始計時,達到逾時還沒有收到ack,這個包就丢失了。
    • 最後發現了丢包也不一定需要重發。是否重發可以和遊戲邏輯結合起來。因為遊戲戰鬥的同步速率很高,丢一個沒有很大影響。
  • 避免擁堵
    • 衡量往返時間(RTT):對我們發送的每個資料包,我們對資料包隊列中包含的序列号和他們發送的時間添加一個登記。

      當我們收到一個應答時,我們找到這個登記并記錄本地時間和我們收到這個應答的時間以及我們發送資料包的時間的不同之處。這是這個資料包的RTT時間。

    • 通過往返時間來調整資料包的個數。當網絡條件好的時候我們每秒發送30個資料包,當網絡條件差的時候我們降至每秒10個資料包。

參考

  • Reliability and Congestion Avoidance over UDP
  • 【翻譯】遊戲網絡開發(四):基于UDP的可靠性,排序和避免擁堵
  • 網絡遊戲 采用的是tcp協定還是udp協定? - fei zhang的回答 - 知乎