【发布时间】:2014-06-28 14:24:27
【问题描述】:
我正在尝试将 LAN 服务器发现添加到我的 Unity 游戏中。我正在使用 UDP 广播请求。如果网络上的任何人是服务器,他们将响应一些服务器数据。我已经弄清楚了这部分,但我需要使用一些 Unity 函数(包括其他自定义的 monobehaviour 脚本)来生成数据包数据。
Unity 不允许从除主线程之外的任何线程访问其 API。
我正在使用UdpClient.BeginReceive、UdpClient.EndReceive、AsyncCallback 流。所以接收 AsyncCallback 函数(下面示例脚本中的AsyncRequestReceiveData)在另一个不允许我使用任何 Unity 函数的线程中运行。
我使用 flamy 的 this answer 作为我的脚本的基础。
当脚本听到请求时,我尝试在AsyncRequestReceiveData 中触发委托和事件,但它似乎在同一个单独的线程中触发。
由单独线程在主线程中触发的事件会很好,但我不确定如何做到这一点。
虽然脚本继承自 MonoBehaviour(Unity 3D 中的基础对象),但它应该可以独立运行。
脚本的输出应如下所示:
发送请求:requestingServers
收到的请求:requestingServers
这是准系统脚本:
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);
}
}
我见过this question (Cleanest Way to Invoke Cross-Thread Events),但我似乎无法弄清楚它是如何工作的以及如何融入其中。
【问题讨论】:
-
@AgentShark Unity 3D 在我的情况下。不过,这个问题并不完全是 Unity 特有的。
标签: c# multithreading sockets unity3d udp