C# 获取UdpClient接收主线程中的数据
我正在尝试将LAN服务器发现添加到我的Unity游戏中。我正在使用UDP来广播请求。如果网络上的任何人是服务器,他们将使用一些服务器数据进行响应。我已经解决了这一部分,但是我需要使用一些Unity函数(包括其他定制的MonoBehavior脚本)来生成数据包数据 Unity不允许从主线程以外的任何线程访问其API 我正在使用,流。因此,receive AsyncCallback函数(C# 获取UdpClient接收主线程中的数据,c#,multithreading,sockets,unity3d,udp,C#,Multithreading,Sockets,Unity3d,Udp,我正在尝试将LAN服务器发现添加到我的Unity游戏中。我正在使用UDP来广播请求。如果网络上的任何人是服务器,他们将使用一些服务器数据进行响应。我已经解决了这一部分,但是我需要使用一些Unity函数(包括其他定制的MonoBehavior脚本)来生成数据包数据 Unity不允许从主线程以外的任何线程访问其API 我正在使用,流。因此,receive AsyncCallback函数(AsyncRequestReceiveData在下面的示例脚本中)在另一个线程中运行,该线程不允许我使用任何Uni
AsyncRequestReceiveData
在下面的示例脚本中)在另一个线程中运行,该线程不允许我使用任何Unity函数
我使用flamy作为我脚本的基础
我曾尝试在脚本听到请求时在AsyncRequestReceiveData
中激发委托和事件,但它似乎在同一个单独的线程中激发
由独立线程在主线程中激发的事件将非常有效,但我不确定如何实现这一点
尽管脚本继承自
monobhavior
(Unity 3D中的基本对象),但它应该可以独立运行
脚本的输出应如下所示:
发送请求:请求服务器
收到的请求:RequestingServer
以下是赤裸裸的脚本:
using UnityEngine;
using System;
using System.Collections;
using System.Net;
using System.Net.Sockets;
public class TestUDP : MonoBehaviour {
public delegate void RequestReceivedEventHandler(string message);
public event RequestReceivedEventHandler OnRequestReceived;
// Use this to trigger the event
protected virtual void ThisRequestReceived(string message)
{
RequestReceivedEventHandler handler = OnRequestReceived;
if(handler != null)
{
handler(message);
}
}
public int requestPort = 55795;
UdpClient udpRequestSender;
UdpClient udpRequestReceiver;
// Use this for initialization
void Start () {
// Set up the sender for requests
this.udpRequestSender = new UdpClient();
IPEndPoint requestGroupEP = new IPEndPoint(IPAddress.Broadcast, this.requestPort);
this.udpRequestSender.Connect(requestGroupEP);
// Set up the receiver for the requests
// Listen for anyone looking for us
this.udpRequestReceiver = new UdpClient(this.requestPort);
this.udpRequestReceiver.BeginReceive(new AsyncCallback(AsyncRequestReceiveData), null);
// Listen for the request
this.OnRequestReceived += (message) => {
Debug.Log("Request Received: " + message);
// Do some more stuff when we get a request
// Use `Network.maxConnections` for example
};
// Send out the request
this.SendRequest();
}
void Update () {
}
void SendRequest()
{
try
{
string message = "requestingServers";
if (message != "")
{
Debug.Log("Sendering Request: " + message);
this.udpRequestSender.Send(System.Text.Encoding.ASCII.GetBytes(message), message.Length);
}
}
catch (ObjectDisposedException e)
{
Debug.LogWarning("Trying to send data on already disposed UdpCleint: " + e);
return;
}
}
void AsyncRequestReceiveData(IAsyncResult result)
{
IPEndPoint receiveIPGroup = new IPEndPoint(IPAddress.Any, this.requestPort);
byte[] received;
if (this.udpRequestReceiver != null) {
received = this.udpRequestReceiver.EndReceive(result, ref receiveIPGroup);
} else {
return;
}
this.udpRequestReceiver.BeginReceive (new AsyncCallback(AsyncRequestReceiveData), null);
string receivedString = System.Text.Encoding.ASCII.GetString(received);
// Fire the event
this.ThisRequestReceived(receivedString);
}
}
我已经看到了,但我似乎不知道它是如何工作的,以及如何融入其中。这个代码示例对您有用吗?可以从任何线程调用X
//place in class where main thread object is
void X(int sampleVariable)
{
if (this.InvokeRequired)
{
this.Invoke((MethodInvoker) (() => X(sampleVariable)));
return;
}
// write main thread code here
}
解决方案的工作原理是跟踪需要在主线程中执行的任务列表(队列),然后通过
HandleTasks()在Update()
中运行该队列;执行并从队列中删除每个队列。您可以通过调用QueueOnMainThread()
并传递匿名函数来添加到任务队列
我从中得到了一些灵感
您可以使用单独的脚本来管理主线程任务,也可以将其合并到您已经存在的脚本中,您需要在主线程中运行一些东西
以下是我在问题中的原始代码片段的固定解决方案
以下是排队和运行所需的位:
// We use this to keep tasks needed to run in the main thread
private static readonly Queue<Action> tasks = new Queue<Action>();
void Update () {
this.HandleTasks();
}
void HandleTasks() {
while (tasks.Count > 0)
{
Action task = null;
lock (tasks)
{
if (tasks.Count > 0)
{
task = tasks.Dequeue();
}
}
task();
}
}
public void QueueOnMainThread(Action task)
{
lock (tasks)
{
tasks.Enqueue(task);
}
}
如果您使用的是WinForms,它有一些很棒的编码模式。@AgentShark在我的例子中。但这个问题并不完全针对Unity。这不起作用,而且大多数方法、类都在Unity中不可用的System.Windows.Forms
中。如果我使用WinForms,还有一些更好的替代模式。
this.QueueOnMainThread(() => {
// We are now in the main thread...
Debug.Log("maxConnections: " + Network.maxConnections);
});