gpt4 book ai didi

c# - 如何使用 Unity 多播 UDP 套接字改进数据同步

转载 作者:行者123 更新时间:2023-12-03 12:02:34 25 4
gpt4 key购买 nike

我正在使用 Unity 和 Sockets 自学一些简单的网络,并且在客户端和服务器之间同步数据时遇到了问题。我知道还有其他使用 Unity Networking 的选项,但在继续之前,我想更好地了解如何使用系统库改进我的代码。
在此示例中,我只是尝试通过多播 UDP 套接字流式传输我的鼠标位置。我正在将一个字符串编码为一个字节数组,并每帧发送一次该数组。我知道将这些值作为字符串发送不是最优的,但除非这可能是瓶颈,否则我假设可以稍后再回来优化它。
我的设置服务器正在以 60 fps 的速度发送值,而客户端正在以相同的速率读取。我遇到的问题是,当客户端收到值时,它通常会一次收到很多。如果我在每帧之间使用 ----- 记录收到的值,我通常会得到如下输出:

------
------
------
------
------
------
------
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 作为一种协议(protocol),要求很少。当然,没有一个可以保证您似乎想要的行为。
可惜没有好的Minimal, Complete, and Verifiable code example ,无法验证您的服务器是否确实在您声称的时间间隔内发送数据。完全有可能你有一个导致这种行为的错误。
但是,如果我们假设代码本身是完美的,那么在使用 UDP 时仍然无法保证数据报不会在沿途的某个时间点被批量处理,从而导致大量数据同时出现在网络缓冲区中。我希望当数据报通过多个网络节点(例如交换机,尤其是通过 Internet)发送时,这种情况会以更高的频率发生,但是当服务器和客户端都在同一台计算机上时,它也很容易发生。
具有讽刺意味的是,一种可能迫使数据报分散得更多的选择是用额外的字节填充每个数据报。所需的确切字节数取决于确切的网络路由;要“完美”地做到这一点,可能需要编写一些校准逻辑,尝试不同的填充量,直到代码看到数据报以它期望的间隔到达。
但这会显着增加网络 I/O 代码的复杂性,但仍不能保证您想要的行为。它有一些明显的负面影响,包括网络上的额外开销(使用计量网络连接的人肯定不会欣赏),以及增加 UDP 数据报被完全丢弃的可能性。
从您的问题中不清楚您的项目是否真的需要多播 UDP,或者这只是您的代码中的某些内容,因为那是您正在使用的一些教程或其他示例。如果实际上不需要多播,那么您绝对应该尝试的另一件事是使用直接 UDP 而不使用多播。
FWIW:我不会按照你的方式实现。相反,我会使用异步接收操作,以便我的客户端在数据报可用时立即接收它们,而不是只定期检查每一帧渲染。我还将在数据报中包含一个序列号,并丢弃(忽略)任何乱序到达的数据报(即序列号不严格大于已收到的最新序列号)。这种方法将提高(可能只是轻微的)响应能力,但也将处理数据报无序到达或重复的情况(使用 UDP 会遇到的三个主要交付问题中的两个……当然,第三个是交货)。

关于c# - 如何使用 Unity 多播 UDP 套接字改进数据同步,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62838610/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com