Unity 中的简单套接字服务器
Posted
技术标签:
【中文标题】Unity 中的简单套接字服务器【英文标题】:Simple socket server in Unity 【发布时间】:2016-07-31 07:05:01 【问题描述】:我想在我的 Unity 项目中使用 C# 插件。该插件应该充当从客户端获取值的服务器,以便我能够使用这些值进行进一步处理。 问题是服务器有无限循环。无限循环会导致 Unity 挂起。如何处理?
编辑:我附上了服务器程序的代码 sn-p。在我看来,有两点可能会导致问题。代码中注释的无限循环和程序暂停点:
void networkCode()
// Data buffer for incoming data.
byte[] bytes = new Byte[1024];
// Establish the local endpoint for the socket.
// Dns.GetHostName returns the name of the
// host running the application.
IPHostEntry ipHostInfo = Dns.Resolve(Dns.GetHostName());
IPAddress ipAddress = ipHostInfo.AddressList[0];
IPEndPoint localEndPoint = new IPEndPoint(ipAddress, 1755);
// Create a TCP/IP socket.
listener = new Socket(ipAddress.AddressFamily,
SocketType.Stream, ProtocolType.Tcp);
// Bind the socket to the local endpoint and
// listen for incoming connections.
try
listener.Bind(localEndPoint);
listener.Listen(10);
// Start listening for connections.
while (true)
// Program is suspended while waiting for an incoming connection.
Debug.Log("HELLO"); //It works
handler = listener.Accept();
Debug.Log("HELLO"); //It doesn't work
data = null;
// An incoming connection needs to be processed.
while (true)
bytes = new byte[1024];
int bytesRec = handler.Receive(bytes);
data += Encoding.ASCII.GetString(bytes, 0, bytesRec);
if (data.IndexOf("<EOF>") > -1)
break;
System.Threading.Thread.Sleep(1);
System.Threading.Thread.Sleep(1);
catch (Exception e)
Debug.Log(e.ToString());
编辑:在@Programmer 的帮助下,C# 插件完成了。但是 Unity 没有读取正确的值。我附上了 Unity 端代码:
using UnityEngine;
using System;
using SyncServerDLL; //That's our library
public class receiver : MonoBehaviour
SynchronousSocketListener obj; //That's object to call server methods
// Use this for initialization
void Start()
obj = new SynchronousSocketListener ();
obj.startServer ();
// Update is called once per frame
void Update()
Debug.Log (obj.data);
我已经在 Visual Studio 中彻底测试了 SynchronousSocketListener 类。它在那里取得了很好的效果。
【问题讨论】:
用你挂起的代码更新你的问题 @Programmer:他提供了解释“挂起”的相关信息:代码是一个无限等待循环,就像您通常在(幼稚的)套接字服务器中编写的那样。问题是他在插件中执行此操作,他在主统一线程中运行。这有效地“挂起”了 Unity。也就是说,一些代码会很好。 @Paul-Jan 添加了一些代码来给出一个粗略的想法。 @Paul-Jan。我知道他遇到的问题。我想通过修复他的代码来提供解决方案,而不是花时间从头开始编写新代码。还想确保他有一些东西并且不希望人们编写他所有的代码。 @Programmer 如果需要,我可以添加更多代码。我可以为自己做编码部分。我只需要一个方向。 【参考方案1】:使用Thread 来做你的服务器监听和读写操作。 您可以将套接字和其他网络流对象声明为公共的,然后在线程函数中对其进行初始化。
Unity 不适用于线程中的 while 循环,有时可能会冻结,但您可以通过在 while
循环中添加 System.Threading.Thread.Sleep(1);
来修复正在读取或等待来自套接字的数据。
确保在OnDisable()
函数中停止线程。请不从新的 Thread 函数访问 Unity API。只需在那里做套接字的事情,然后将数据返回到 public 变量。
System.Threading.Thread SocketThread;
volatile bool keepReading = false;
// Use this for initialization
void Start()
Application.runInBackground = true;
startServer();
void startServer()
SocketThread = new System.Threading.Thread(networkCode);
SocketThread.IsBackground = true;
SocketThread.Start();
private string getIPAddress()
IPHostEntry host;
string localIP = "";
host = Dns.GetHostEntry(Dns.GetHostName());
foreach (IPAddress ip in host.AddressList)
if (ip.AddressFamily == AddressFamily.InterNetwork)
localIP = ip.ToString();
return localIP;
Socket listener;
Socket handler;
void networkCode()
string data;
// Data buffer for incoming data.
byte[] bytes = new Byte[1024];
// host running the application.
Debug.Log("Ip " + getIPAddress().ToString());
IPAddress[] ipArray = Dns.GetHostAddresses(getIPAddress());
IPEndPoint localEndPoint = new IPEndPoint(ipArray[0], 1755);
// Create a TCP/IP socket.
listener = new Socket(ipArray[0].AddressFamily,
SocketType.Stream, ProtocolType.Tcp);
// Bind the socket to the local endpoint and
// listen for incoming connections.
try
listener.Bind(localEndPoint);
listener.Listen(10);
// Start listening for connections.
while (true)
keepReading = true;
// Program is suspended while waiting for an incoming connection.
Debug.Log("Waiting for Connection"); //It works
handler = listener.Accept();
Debug.Log("Client Connected"); //It doesn't work
data = null;
// An incoming connection needs to be processed.
while (keepReading)
bytes = new byte[1024];
int bytesRec = handler.Receive(bytes);
Debug.Log("Received from Server");
if (bytesRec <= 0)
keepReading = false;
handler.Disconnect(true);
break;
data += Encoding.ASCII.GetString(bytes, 0, bytesRec);
if (data.IndexOf("<EOF>") > -1)
break;
System.Threading.Thread.Sleep(1);
System.Threading.Thread.Sleep(1);
catch (Exception e)
Debug.Log(e.ToString());
void stopServer()
keepReading = false;
//stop thread
if (SocketThread != null)
SocketThread.Abort();
if (handler != null && handler.Connected)
handler.Disconnect(false);
Debug.Log("Disconnected!");
void OnDisable()
stopServer();
【讨论】:
我会尝试一下,然后会回复你。此外,服务器当前是同步服务器。是好的还是应该是异步的? 您没有调用networkCode
或Start()
方法。您调用startServer();
方法。 Start()
方法在游戏启动时由 Unity 自动调用。你调用startServer();
代码,我已经从Start()
调用它。请查看我上面发布的代码,如果您不知道如何以及何时调用 Start()
,我建议您学习 Unity API。
当startServer()
被调用时,它会创建一个指向networkCode
函数的线程,并且该线程将在SocketThread.Start();
在startServer()
函数中被调用之后调用networkCode()
函数。
好的。我建议您在 Unity 开发过程中将 IsBackground 设置为 true,否则 Unity 中会运行许多线程导致套接字无法正确断开连接。当您有 1 个套接字仍在侦听时,如果您尝试在 Unity 中再次测试代码,则会出现错误。本主题是高级主题,但当您有时间了解后台线程和前台线程之间的区别时,请阅读有关 IsBackground 的内容。
我花时间修复这些东西。不要改变任何东西,否则你会得到新的错误。你不需要异步。哦,记得删除 startServer();在将其编译为插件之前从 Start 开始,这样您就不会调用它两次。然后你可以调用 startServer();从主应用程序中的 Start() 开始。经 Hercules 测试,一切正常 100%。没有冻结或错误。不客气!以上是关于Unity 中的简单套接字服务器的主要内容,如果未能解决你的问题,请参考以下文章
Unity 如何连接基于 Node.js 的 Secure WebSocket?