對 UDP 的一些思考


先放兩個鏈接

快速可靠協議-KCP

可靠 UDP 傳輸

 

最近在玩王者榮耀,發覺兩件事:

1. 可以 4G 和 wifi 無痛切換

2. 當網絡不好的時候,發出去的消息並不保證到達服務器。比如你在很卡的時候做了某些操作,等網絡恢復之后你會發現,你還是在某個沒有做那些操作之前的狀態

 

結合這兩周閱讀的 KCP,我能想到的是,對於第 1 點基於 KCP 就可以實現。

初讀 KCP 的時候,對 conv 變量的存在十分不理解,為什么要用它來表示一個會話,直接由 recvfrom 返回的源 IP 和 port 做 key,找到對應的 ikcpcb 不好么。

有這個想法是因為腦海中始終還想着 TCP 那一套,也就是 用一個四元組來唯一確定一個連接。直到我后來再次想到上面第 1 個問題,才想明白,在 UDP 之上定義連接的概念,如果還是將它跟四元組綁在一起,那無非是實現了另一個 TCP。而當你用一個 conv 變量來標識一個連接時,這個協議的連接也就天然的跟源 IP 和 port 無關,也就是隨便你變換 IP 地址和端口,只要你發來的 conv 是一樣的,我就認為你是同一個用戶。當然,代價就是你得開始關心 conv 的生成與校驗,這又是另一個話題。

 

對於第 2 種情況(暫且不論這種做法是否玩家體驗最好),卻不像 KCP 的行為,因為 KCP 是能保證發出去的數據包一定到達服務器的。

而雲風那篇博客里提到的以請求的方式來保證 UDP 的可靠,貌似恰好可以做到符合王者榮耀的表現。也就是可以做到:1. 允許丟包  2. sn 嚴格遞增

可問題是 服務器發給客戶端的數據是不允許丟失的,這可怎么辦。。

協議層沒給的承諾,只好有業務層來做咯~

首先是幀同步,並且服務器會保存當前這一場的所有幀的數據。那么如果客戶端收到了編號為 1,2,5 的數據幀,當收到編號 5 的數據幀時,發現沒有收到 3,4 幀,就要向服務端索要丟失的這兩幀數據。也就是在客戶端的業務層也實現一套請求機制,只不過客戶端業務層請求的是數據幀而不是協議層的數據包,服務端對數據幀是沒有過期時間的,所以客戶端發了請求就一定能求來數據幀!

還有一個問題,就是在游戲大廳時,服務器發給客戶端的消息,也要保證送達,這個怎么辦?因為大廳里的消息並非所謂幀同步,理論上服務器也不會保存那些臨時消息,所以如果還是基於這種請求模式的話貌似就不太靠譜了。我個人感覺這個時候用 KCP 比較好。當然,場內也可以用 KCP,只不過是另外一種效果。

 

總結一下這兩種模式:

1. ack + 超時重傳  ->   KCP    可靠     快速重傳    但是當網絡差到快速重傳也發不到的時候,服務器會堆積大量需要重傳的數據包

2.  req  -> rudp   會丟包    但是保證包的順序     不管網絡好壞,服務器發送數據都很平穩

 

 

更新

修改 KCP 也可以實現王者榮耀的效果。

ikcp_send 前,先檢查 ikcp_waitsnd,如果 waitsnd 大於某個閾值比如 64,則認為當前網絡太差,然后不調用 ikcp_send,丟棄這個數據(或者上層消息隊列繼續緩存這個數據,從王者的表現來看是直接丟棄的)。同時啟動一個計時器,如果 waitsnd 持續 10s 都大於 64,則認為網絡奇差無比,根本無法游戲,銷毀 kcpcb,斷線處理。如果 10s 內 waitsnd 一旦小於 32,則認為網絡恢復正常,取消掉前面的計時器。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM