Unity UNet проблема со связью: интервал прибытия сообщения не согласован и пакетное прибытие
Я построил очень простую низкоуровневую передачу сообщений UNet (LLAPI) между клиентом и сервером, где я отправляю только Vector3 с сервера на клиент. И серверное, и клиентское приложение работают на одном компьютере. Запуск Windows 10 и Unity 2018.2.15f1.
Я пытался отправлять сообщения каждый цикл обновления (средний интервал передачи 16 мс), и на клиенте я замечаю, что от 40% до 50% полученных сообщений приходят в один и тот же момент времени (т. Е. Вы получаете пакетное поступление сообщений как 2 или более сообщения приходят в одно и то же время). Чтобы измерить это, я установил секундомер, который проверяет прошедшее время между приходом сообщений. Секундомер реализован внутри обратного вызова при приеме сообщения. Это довольно проблематично, так как если вы обновляете позу объекта и два сообщения позы приходят одновременно, то только последнее сообщение используется для обновления позы объекта.
Затем я попытался отправлять сообщения каждый второй цикл обновления (средний интервал передачи 33 мс). В этом случае на клиенте нет сообщений, поступающих одновременно, но 20% сообщений поступают с интервалом, превышающим 36 мс.
Кто-нибудь тоже сталкивался с этой проблемой? Есть ли рекомендуемое решение этой проблемы? Моя цель - отправлять сообщения с частотой 60 Гц и получать их с одинаковой скоростью без большой задержки.
В случае, если кто-то захочет попробовать код, вот сценарии сервера и клиента.
Это сервер:
using UnityEngine.Networking;
public class ServerScript : MonoBehaviour
{
private const short ClientToServerMsgIdHaptic = 3007;
public bool isAtStartup = true;
private System.Diagnostics.Stopwatch stopWatch;
private double lastTimeStamp;
private double currentTimeStamp;
private float pktCounter0 = 0;
private float pktCounterHighDelay = 0;
private float pktCounterHighDelayX = 0;
private float pktCountertotal = 0;
private double avgtime = 0;
private double avgtimeAcc = 0;
public class ClientToServerMessage : MessageBase
{
public Vector3 posObj;
}
void Update()
{
if (isAtStartup)
{
SetupServer();
Debug.Log("Server is running");
}
// print the avg arrival time after 1000 packets are received
if(pktCountertotal == 1000)
{
avgtime = avgtimeAcc / pktCountertotal;
Debug.Log("Average time " + avgtime);
}
}
// Create a client and connect to the server port
public void SetupServer()
{
NetworkServer.RegisterHandler(ClientToServerMsgIdHaptic, OnCommandReceive);
NetworkServer.Listen(4444);
isAtStartup = false;
Debug.Log("Server has started");
stopWatch = new System.Diagnostics.Stopwatch();
stopWatch.Start();
lastTimeStamp = 0;
pktCounterHighDelay = 0;
}
public void OnCommandReceive(NetworkMessage netMsg)
{
ClientToServerMessage Message = netMsg.ReadMessage<ClientToServerMessage>();
transform.position = Message.posObj;
currentTimeStamp = stopWatch.ElapsedMilliseconds - lastTimeStamp;
lastTimeStamp = stopWatch.ElapsedMilliseconds;
// burst arrival
if (currentTimeStamp <= 2)
{
pktCounter0 = pktCounter0 + 1;
}
// delay larger than 36
if (currentTimeStamp > 36)
{
pktCounterHighDelay++;
}
// delay larger than 51
if (currentTimeStamp > 51)
{
pktCounterHighDelayX++;
}
pktCountertotal = pktCountertotal + 1;
avgtimeAcc = avgtimeAcc + currentTimeStamp;
Debug.Log("Time between received messages" + currentTimeStamp.ToString("F2") + " pkttotal0 " + pktCounter0 + " pktotal " + pktCountertotal + " pkts high delay " + pktCounterHighDelay + " pkts high delay X " + pktCounterHighDelayX);
}
}
А вот и клиент
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Networking;
using UnityEngine.Networking.NetworkSystem;
public class ClientScript : MonoBehaviour {
// Definitions
NetworkClient myClient;
private bool isAtStartup = true;
private const short ClientToServerMsgId = 3007;
private bool isConnected = false;
private float counter = 0;
private System.Diagnostics.Stopwatch stopWatch;
private double lastTimeStamp;
private double currentTimeStamp;
public class ClientToServerMessage : MessageBase
{
public Vector3 posObj;
}
// Create a client and connect to the server port
public void SetupClient()
{
myClient = new NetworkClient();
myClient.RegisterHandler(MsgType.Connect, OnConnected);
myClient.Connect("YOUR IP ADDRESS", 4444);
isAtStartup = false;
Debug.Log("Setting up client");
stopWatch = new System.Diagnostics.Stopwatch();
stopWatch.Start();
lastTimeStamp = 0;
}
// Use this for initialization
void Start () {
if (isAtStartup) // if at startup start the client
{
SetupClient();
}
}
// Update is called once per frame
void Update () {
var x = Input.GetAxis("Horizontal") * Time.deltaTime * 150.0f;
var z = Input.GetAxis("Vertical") * Time.deltaTime * 3.0f;
transform.Rotate(0, x, 0);
transform.Translate(0, 0, z);
if (isConnected)
{
// to send every update loop: counter = 0
// to send every second update loop: counter = 1
if (counter == 0)
{
ClientToServerMessage msg = new ClientToServerMessage();
msg.posObj = transform.position;
currentTimeStamp = stopWatch.ElapsedMilliseconds - lastTimeStamp;
lastTimeStamp = stopWatch.ElapsedMilliseconds;
Debug.Log("Time between transmitted messages" + currentTimeStamp.ToString("F2"));
myClient.Send(ClientToServerMsgId, msg);
counter = -1;
}
counter = counter + 1;
}
}
// Create Connected successfull flag
public void OnConnected(NetworkMessage netMsg)
{
Debug.Log("Connected to server");
isConnected = true;
}
}