HoloLens2 -UWP-application中极端的UDP包装损失
在我的HoloLens2应用程序中,有时UDP包装速率从每秒40个包装下降到每秒40个包裹降至每秒0-2个包裹并留在那里(2000字节和60000个字节之间的包装大小。该应用程序是用Unity3D和.NET插座制成的。对于网络,有时会在30分钟内直接发生,因此,在这种情况下,安静的是随机的。可以毫无问题地处理网络流量
。 还是HoloLens2在通过以太网(而不是wifi)运行时的bandwith有限?
同时,我的应用程序还维护了点对点视频流(带有混合捕获的WebRTC)。该流在应用程序的整个生命周期内都很好地工作。
using System;
using System.Collections;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using UnityEngine;
public class UdpCommunicationDotNet : ICommunicator
{
#region Fields
private int m_PackageCountPerSecond;
private int m_PackageCountTotal;
private Thread m_PackageCounterResetRoutine;
private Socket m_SenderSocket;
private Socket m_ReceiverSocket;
private IPEndPoint m_ServerIpEndPoint;
private IPEndPoint m_ReceiverIpEndPoint;
private IPEndPoint m_ListenerIpEndPoint;
private EndPoint m_ServerEndPoint;
private EndPoint m_ReceiverEndPoint;
private byte[] m_ReceiveBuffer;
private IDataProvider m_DataProvider;
private int m_MaxBufferByteLength;
private bool m_ReceiveEnabled = true;
public IDataProvider DataProvider { get => m_DataProvider; set => m_DataProvider = value; }
#endregion
#region Constructor
public UdpCommunicationDotNet()
{
m_MaxBufferByteLength = GameManager.Instance.GetConfigurationManager.RuntimeConfig.NetworkSettings.MaxBufferByteLength;
}
#endregion
#region Public Methods
public void Initialize(DataLineConfig dataLineConfig)
{
m_ReceiveBuffer = new byte[m_MaxBufferByteLength];
m_ServerIpEndPoint = dataLineConfig.serverEndPoint;
m_ReceiverIpEndPoint = new IPEndPoint(IPAddress.Any, 0);
m_ServerEndPoint = (EndPoint)m_ServerIpEndPoint;
m_ReceiverEndPoint = (EndPoint)m_ReceiverIpEndPoint;
m_ListenerIpEndPoint = dataLineConfig.receiverEndPoint;
}
public void StartReceiver()
{
if (InitializeReceiverSocket())
{
m_ReceiveEnabled = true;
StartReceiving();
}
}
public void EndReceiver()
{
m_ReceiveEnabled = false;
}
public void StartSender()
{
InitializeSenderSocket();
}
public void Send(Byte[] data)
{
try
{
//added this, remove it
//Debug.Log("SentMyDataPackage");
m_SenderSocket.BeginSendTo(data, 0, data.Length, SocketFlags.None, m_ServerEndPoint, new AsyncCallback(OnSendCallback), null);
}
catch (Exception e)
{
Debug.LogError("Failed to send udp data through the UdpCommunicator: " + e.Message);
}
}
#endregion
#region Private Methods
private bool InitializeReceiverSocket()
{
bool isInitialized = false;
try
{
m_ReceiverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
m_ReceiverSocket.Bind(m_ListenerIpEndPoint);
isInitialized = true;
}
catch (Exception e)
{
Debug.LogError("Failed to initialize the receiver socket in the UdpCommunicator: " + e.Message);
}
return isInitialized;
}
private void InitializeSenderSocket()
{
m_SenderSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
}
private void StartReceiving()
{
m_ReceiverSocket.BeginReceiveFrom(m_ReceiveBuffer, 0, m_ReceiveBuffer.Length, SocketFlags.None, ref m_ReceiverEndPoint, new AsyncCallback(OnReceiveCallback), m_ReceiverEndPoint);
}
private void DistributeData(object dataObject)
{
byte[] data = (byte[])dataObject;
m_DataProvider.DistributeData(data);
}
#endregion
#region Callback Methods
private void OnSendCallback(IAsyncResult asyncResult)
{
try
{
m_SenderSocket.EndSend(asyncResult);
}
catch (Exception e)
{
Debug.LogError("Failed to close the opened send connection in the UdpCommunicator: " + e.Message);
}
}
private void OnReceiveCallback(IAsyncResult asyncResult)
{
try
{
if (DebugManager.Instance.isActive)
{
DebugManager.Instance.m_PackageCounter.UpdateMainCountTotal(m_PackageCountTotal);
}
int receivedBufferSize = m_ReceiverSocket.EndReceiveFrom(asyncResult, ref m_ReceiverEndPoint);
Array.Resize(ref m_ReceiveBuffer, receivedBufferSize);
byte[] copiedBuffer = new byte[receivedBufferSize];
Buffer.BlockCopy(m_ReceiveBuffer, 0, copiedBuffer, 0, receivedBufferSize);
Thread thread = new Thread(DistributeData);
thread.SetApartmentState(ApartmentState.STA);
thread.Start(copiedBuffer);
m_ReceiveBuffer = new byte[m_MaxBufferByteLength];
}
catch (Exception e)
{
Debug.LogError("Failed to fetch the received data in the UdpCommunicator: " + e.Message);
}
finally
{
if (m_ReceiveEnabled)
{
StartReceiving();
}
else
{
m_ReceiverSocket.Shutdown(SocketShutdown.Both);
m_SenderSocket.Shutdown(SocketShutdown.Both);
m_ReceiverSocket.Close();
m_SenderSocket.Close();
}
}
}
#endregion
}
编辑: 通过写下最小的可重现示例,我发现了小姐的原因!我意识到,如果我在一个块中发送超过4个软件包(因此,发送package1,send package2,send package3,send package4等,等待x ms,重新开始)HoloLens2开始放下我的UDP软件包。
相比之下,当我发送软件包1->等待4毫秒 - >发送软件包2->等待4毫秒 - >发送包3->等待4ms,等等,等等,在发送所有不同的包装之后,仅重新启动发送,它就像魅力一样!
另外,当我通过以太网发送软件包(对于我的案件中不是可用的方法)时,即使我在一个块中发送了所有软件包,也可以使用。
对我而言,这种行为既适合又可以向自己解释。也许你们中的人可以吗?无论如何,感谢任何试图帮助我的人!
In my HoloLens2 application sometimes the UDP-Package-receive rate drops instantly from 40 packages per second to 0-2 packages per second and stays there (size of packages between 2000 byte and 60000 byte. The application is made with Unity3d and .Net Sockets for networking. This behaviour sometimes happens straight from application startup, sometimes after 30 minutes, so basically quiet random. Even Restarting HoloLens2 doesn´t help in such a situation. The application logs no exception or error messages. On my Unity-Editor the Application can handle the network traffic without any problem.
It feels like some Network buffer got stuffend and drops all packages so did I miss some Cleanup command in my Networking-Code or is there another way to face Receive-Overload in my code?
Or is HoloLens2 somehow limited in it´s Bandwith when running via Ethernet (and not Wifi)?
At the same time my application also maintains a peer-to-peer Video-stream (WebRTC with MixedReality Capture). This stream works well over the whole lifetime of the application flawlessly.
using System;
using System.Collections;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using UnityEngine;
public class UdpCommunicationDotNet : ICommunicator
{
#region Fields
private int m_PackageCountPerSecond;
private int m_PackageCountTotal;
private Thread m_PackageCounterResetRoutine;
private Socket m_SenderSocket;
private Socket m_ReceiverSocket;
private IPEndPoint m_ServerIpEndPoint;
private IPEndPoint m_ReceiverIpEndPoint;
private IPEndPoint m_ListenerIpEndPoint;
private EndPoint m_ServerEndPoint;
private EndPoint m_ReceiverEndPoint;
private byte[] m_ReceiveBuffer;
private IDataProvider m_DataProvider;
private int m_MaxBufferByteLength;
private bool m_ReceiveEnabled = true;
public IDataProvider DataProvider { get => m_DataProvider; set => m_DataProvider = value; }
#endregion
#region Constructor
public UdpCommunicationDotNet()
{
m_MaxBufferByteLength = GameManager.Instance.GetConfigurationManager.RuntimeConfig.NetworkSettings.MaxBufferByteLength;
}
#endregion
#region Public Methods
public void Initialize(DataLineConfig dataLineConfig)
{
m_ReceiveBuffer = new byte[m_MaxBufferByteLength];
m_ServerIpEndPoint = dataLineConfig.serverEndPoint;
m_ReceiverIpEndPoint = new IPEndPoint(IPAddress.Any, 0);
m_ServerEndPoint = (EndPoint)m_ServerIpEndPoint;
m_ReceiverEndPoint = (EndPoint)m_ReceiverIpEndPoint;
m_ListenerIpEndPoint = dataLineConfig.receiverEndPoint;
}
public void StartReceiver()
{
if (InitializeReceiverSocket())
{
m_ReceiveEnabled = true;
StartReceiving();
}
}
public void EndReceiver()
{
m_ReceiveEnabled = false;
}
public void StartSender()
{
InitializeSenderSocket();
}
public void Send(Byte[] data)
{
try
{
//added this, remove it
//Debug.Log("SentMyDataPackage");
m_SenderSocket.BeginSendTo(data, 0, data.Length, SocketFlags.None, m_ServerEndPoint, new AsyncCallback(OnSendCallback), null);
}
catch (Exception e)
{
Debug.LogError("Failed to send udp data through the UdpCommunicator: " + e.Message);
}
}
#endregion
#region Private Methods
private bool InitializeReceiverSocket()
{
bool isInitialized = false;
try
{
m_ReceiverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
m_ReceiverSocket.Bind(m_ListenerIpEndPoint);
isInitialized = true;
}
catch (Exception e)
{
Debug.LogError("Failed to initialize the receiver socket in the UdpCommunicator: " + e.Message);
}
return isInitialized;
}
private void InitializeSenderSocket()
{
m_SenderSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
}
private void StartReceiving()
{
m_ReceiverSocket.BeginReceiveFrom(m_ReceiveBuffer, 0, m_ReceiveBuffer.Length, SocketFlags.None, ref m_ReceiverEndPoint, new AsyncCallback(OnReceiveCallback), m_ReceiverEndPoint);
}
private void DistributeData(object dataObject)
{
byte[] data = (byte[])dataObject;
m_DataProvider.DistributeData(data);
}
#endregion
#region Callback Methods
private void OnSendCallback(IAsyncResult asyncResult)
{
try
{
m_SenderSocket.EndSend(asyncResult);
}
catch (Exception e)
{
Debug.LogError("Failed to close the opened send connection in the UdpCommunicator: " + e.Message);
}
}
private void OnReceiveCallback(IAsyncResult asyncResult)
{
try
{
if (DebugManager.Instance.isActive)
{
DebugManager.Instance.m_PackageCounter.UpdateMainCountTotal(m_PackageCountTotal);
}
int receivedBufferSize = m_ReceiverSocket.EndReceiveFrom(asyncResult, ref m_ReceiverEndPoint);
Array.Resize(ref m_ReceiveBuffer, receivedBufferSize);
byte[] copiedBuffer = new byte[receivedBufferSize];
Buffer.BlockCopy(m_ReceiveBuffer, 0, copiedBuffer, 0, receivedBufferSize);
Thread thread = new Thread(DistributeData);
thread.SetApartmentState(ApartmentState.STA);
thread.Start(copiedBuffer);
m_ReceiveBuffer = new byte[m_MaxBufferByteLength];
}
catch (Exception e)
{
Debug.LogError("Failed to fetch the received data in the UdpCommunicator: " + e.Message);
}
finally
{
if (m_ReceiveEnabled)
{
StartReceiving();
}
else
{
m_ReceiverSocket.Shutdown(SocketShutdown.Both);
m_SenderSocket.Shutdown(SocketShutdown.Both);
m_ReceiverSocket.Close();
m_SenderSocket.Close();
}
}
}
#endregion
}
Edit:
By writing the Minimal Reproducable Example I found out the reason for the missbehaviour! I realized that if I send more than 4 Packages in one chunk (so send package1, send package2, send package3, send package4, etc, wait x ms, start again) HoloLens2 is starting to drop my udp packages.
In contrast, when I send Package1-> wait for 4 ms -> send package2 -> wait for 4 ms -> send package 3 -> wait 4ms and so on and after sending all different packages simply restart sending, it Works like a charm!
Also, when I send the packages via EthernetOverUSB (what is not a usable approach for my case), even if I send all packages in one chunk it works.
For me this behaviour is wiered and I can´t explain it to myself. Maybe somebody of you can ? Anyways, thanks for anybody who tried to help me!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论