網絡遊戲實現UDP通訊

####UDP協議特色:c#

1:不保證報文必定到達服務器

2:沒有鏈接的概念網絡

3:不保證報文按順序到達設計

4:發送的是整個包,而不是數據流code

####UDP適合傳輸的數據對象

對於網絡遊戲中,玩家的座標位置和朝向的同步,可使用UDP協議來進行,由於座標和朝向只須要同步最新的值,中間移動過程,並非很是重要。隊列

####實現遊戲

結合使用TCP和UDP兩個協議,能夠比較容易實現以上應用。路由

首先在客戶端和服務器之間創建一條可靠的TCP鏈接字符串

由於UDP是無鏈接的所以,須要實現創建一條UDP鏈接的協議流程。

接着使用三段握手的方式,創建UDP鏈接,若是沒法創建UDP鏈接,則遊戲運行時應該使用TCP鏈接進行數據發送。

三段握手實現:首先客戶端發送 請求,例如BeginUDP 到服務端監聽的端口上,服務端根據收到的客戶端鏈接,向客戶端發送EndUDP, 客戶端若是收到了EndUDP 協議,則客戶端使用TCP通道發送一個UDPSuccess 報文給服務器,由於TCP可靠,所以服務器是必定會受到這個UDPSuccess 報文的。

經過使用三段握手,以及TCP協議,就避免了半鏈接問題,即客戶端有到服務器的UDP鏈接,而服務器沒有到客戶端的UDP鏈接,或者服務器有到客戶端的UDP鏈接,而客戶端沒有創建鏈接成功。

若是創建鏈接失敗,則遊戲繼續使用TCP進行正常的數據通訊。

####須要注意一點

有些路由器限制了UDP鏈接的創建,客戶端A在路由器和交換機 NAT內部,而服務器B在公網上,要創建UDP鏈接就須要作一個隧道,而有些路由限制,B若是想向A發送報文,則B必須使用A鏈接本身的端口發送,不然B的報文沒法到達A, 這個稱爲 對稱路由, 也就是B不能換個端口,而後向A發送UDP報文,這樣報文是沒法到達的。

####客戶端網絡和服務器網絡設計

這裏使用c#語言來實現,c#中有一個UDPClient類能夠用於實現UDP相關功能

服務器上對於每一個客戶端的UDP鏈接有個 UDPAgent類進行管理

服務器上只有一個UDPClient 對象,這個對象負責全部的報文的接受和發送

每次服務器想要向客戶端發送報文,都須要將報文先存入報文隊列,接着經過UDPClient 一個一個發送出去

每次服務器接收到新的報文,根據報文來源IP和端口,將其分發到不一樣的UDPAgent中進行處理

客戶端握手協議實現: 發送 BeginUDP 等待服務器發送EndUDP, 若是超時,則UDP鏈接創建失敗,網絡通訊將只使用TCP處理 收到EndUDP,以TCP協議發送 UDPSuccess 給服務器

服務端握手協議實現: 收到客戶端的BeginUDP 報文 以UDP協議發送EndUDP 報文 收到TCP 發送的UDPSuccess報文

報文除了有BeginUDP字符串以外,還有服務器分配的玩家的Id信息,經過這個ID信息來標識不一樣的玩家,而ID 是經過TCP來初始化的。

####移動報文協議

在移動報文中有一個FrameID 用於標識每一個UDP報文的編號,這個FrameID是byte類型

UDP無序,不可靠,如何保證服務器只使用最新的移動報文,而對舊的移動報文直接丟棄掉呢?

每次收到新的報文,和以前收到的最大的FrameID 比較,若是比之大,則是一個最新的位置信息報文,對齊進行處理。

可是FrameID在255以後就會變爲0,如何解決整數byte範圍有限的問題呢?

1:簡單方案可使用一個更大的數據類型,例如long

2:第二個方案:將0-255分紅兩部分,0-127 和 128-255,每次進入新的一段,須要使用TCP協議來通知服務器和客戶端, FrameId區間發生了變化,再收到這個可靠地區間變化協議的時候,強制修改上次收到的最大的FrameID這個字段lastMaxFrameID

那麼移動報文處理流程以下:

1:客戶端以當前FrameID 發送位置報文,若是FrameID==0 或者FrameID==128,則使用TCP協議,不然使用UDP協議, 報文中須要標記該報文是否爲可靠報文

2:服務器接收到報文,若是標記了可靠,則強制修改服務器的LastFrameID 爲當前報文的FrameID 服務器將移動報文廣播出去
服務器在廣播的時候,若是發現當前爲可靠報文,則標記一下當前報文的可靠性,將其以TCP廣播,不然以UDP廣播給全部客戶端

3: 客戶端收到服務器的報文,若是爲可靠則強制修改,不然拋棄掉舊報文,只處理新報文

之因此要切割成兩段,是由於,UDP自己不可靠,可能報文從240 到255都丟失了,255到10也丟失了,這時候報文 11到來,須要處理這種狀況

相關文章
相關標籤/搜索