簡體   English   中英

如何使用 Unity 多播 UDP 套接字改進數據同步

[英]How to improve data synchronization using Unity an multicast UDP socket

我正在使用 Unity 和 Sockets 自學一些簡單的網絡,並且在客戶端和服務器之間同步數據時遇到了問題。 我知道還有其他使用 Unity Networking 的選項,但在繼續之前,我想更好地了解如何使用系統庫改進我的代碼。

在此示例中,我只是嘗試通過多播 UDP 套接字對我的鼠標 position 進行 ZF7B44CFFAFD5C52223D5498196C8A2E7BZ。 我正在將一個字符串編碼為一個字節數組,並每幀發送一次該數組。 我知道將這些值作為字符串發送不是最優的,但除非這可能是瓶頸,否則我假設可以稍后再回來優化它。

我的設置服務器正在以 60 fps 的速度發送值,而客戶端正在以相同的速率讀取。 我遇到的問題是,當客戶端收到值時,它通常會一次收到很多。 如果我在每幀之間用-----記錄我收到的值,我通常會得到 output ,如下所示:

------
------
------
------
------
------
------
119,396
91,396
45,391
18,379
-8,362
-35,342
-59,314
------
------
------
------
------
------
------

我希望不同步的更新周期會導致每幀接收兩個值,但我不確定是什么導致了更大的差異。

這是服務器代碼:

using UnityEngine;
using System.Net;
using System.Net.Sockets;
using System.Text;

public class Server : MonoBehaviour
{
    Socket _socket;

    void OnEnable ()
    {
        var ip = IPAddress.Parse ("224.5.6.7");
        var ipEndPoint = new IPEndPoint(ip, 4567);

        _socket = new Socket (AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
        _socket.SetSocketOption (SocketOptionLevel.IP, SocketOptionName.AddMembership, new MulticastOption (ip));
        _socket.SetSocketOption (SocketOptionLevel.IP, SocketOptionName.MulticastTimeToLive, 2);
        _socket.Connect(ipEndPoint);
    }

    void OnDisable ()
    {
        if (_socket != null)
        {
            _socket.Close();
            _socket = null;
        }
    }

    public void Send (string message)
    {
        var byteArray = Encoding.ASCII.GetBytes (message);
        _socket.Send (byteArray);
    }
}

和客戶:

using UnityEngine;
using System.Net;
using System.Net.Sockets;
using System.Text;

public class Client : MonoBehaviour
{
    Socket _socket;
    byte[] _byteBuffer = new byte[16];

    public delegate void MessageRecievedEvent (string message);
    public MessageRecievedEvent messageWasRecieved = delegate {};
    

    void OnEnable ()
    {
        var ipEndPoint = new IPEndPoint(IPAddress.Any, 4567);
        var ip = IPAddress.Parse("224.5.6.7");

        _socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
        _socket.Bind (ipEndPoint);
        _socket.SetSocketOption (SocketOptionLevel.IP, SocketOptionName.AddMembership, new MulticastOption(ip,IPAddress.Any));
    }

    void Update ()
    {
        while (_socket.Available > 0)
        {
            for (int i = 0; i < _byteBuffer.Length; i++) _byteBuffer[i] = 0;
            _socket.Receive (_byteBuffer);
            messageWasRecieved (Encoding.ASCII.GetString (_byteBuffer));
        }
    }
}

如果有人能闡明我可以做些什么來改善同步,那將是一個很大的幫助。

網絡 I/O 受到大量外部影響,而 TCP/IP 作為協議要求很少。 當然,沒有一個可以保證您似乎想要的行為。

不幸的是,如果沒有一個好的Minimal、Complete 和 Verifiable 代碼示例,就無法驗證您的服務器是否確實以您聲稱的時間間隔發送數據。 完全有可能你有一個導致這種行為的錯誤。

但是,如果我們假設代碼本身是完美的,那么在使用 UDP 時仍然無法保證數據報不會在沿途的某個時間點被批量處理,從而導致大量數據同時出現在網絡緩沖區中。 當數據報通過多個網絡節點(例如交換機,尤其是通過 Internet)發送時,我希望這種情況發生的頻率更高,但是當服務器和客戶端都在同一台計算機上時,它也很容易發生。

具有諷刺意味的是,一種可能迫使數據報分散得更多的選擇是用額外的字節填充每個數據報。 所需的確切字節數取決於確切的網絡路由; 要“完美”地做到這一點,可能需要編寫一些校准邏輯,嘗試不同的填充量,直到代碼看到數據報以它期望的間隔到達。

但這會顯着增加網絡 I/O 代碼的復雜性,但仍不能保證您想要的行為。 它有一些明顯的負面影響,包括網絡上的額外開銷(使用計量網絡連接的人肯定不會欣賞),以及增加了 UDP 數據報被完全丟棄的可能性。

從您的問題中不清楚您的項目是否真的需要多播 UDP,或者這只是您的代碼中的某些內容,因為這是您正在使用的一些教程或其他示例。 如果實際上不需要多播,那么您絕對應該嘗試的另一件事是直接使用 UDP 而不進行多播。

FWIW:我不會按照你的方式實施。 相反,我會使用異步接收操作,以便我的客戶端在數據報可用時立即接收它們,而不是只定期檢查每一幀渲染。 我還將在數據報中包含一個序列號,並丟棄(忽略)任何亂序到達的數據報(即序列號不嚴格大於已收到的最新序列號)。 這種方法將提高(也許只是輕微的)響應能力,但也將處理數據報無序到達或重復的情況(使用 UDP 會遇到的三個主要交付問題中的兩個……當然,第三個是送貨)。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM