Простой сокет-сервер в Unity
Я хочу использовать плагин C# в своем проекте Unity. Этот плагин должен действовать как сервер, который будет получать значения от клиента, чтобы я мог использовать эти значения для дальнейшей обработки. Проблема в том, что сервер имеет бесконечный цикл. А бесконечные петли приводят к зависанию Unity. Как справиться с этим?
РЕДАКТИРОВАТЬ: я прилагаю фрагмент кода серверной программы. На мой взгляд, есть 2 момента, которые могут вызывать проблемы. Бесконечные циклы и точка, в которой программа приостановлена, как прокомментировано в коде:
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);
}
}
Я тщательно протестировал класс SynchronousSocketListener в Visual Studio. Это дает хорошие результаты там.
1 ответ
Используйте поток, чтобы сделать ваш сервер Слушайте и читать и писать действия. Вы можете объявить сокет и другие объекты сетевого потока как общедоступные, а затем инициализировать их в функции потока.
Unity плохо работает с циклами while в потоках и может иногда зависать, но это можно исправить, добавив System.Threading.Thread.Sleep(1);
в вашем while
Цикл, в котором вы читаете или ожидаете получения данных из сокета.
Не забудьте остановить поток в OnDisable()
функция. НЕ обращайтесь к Unity API из новой функции Thread. Просто сделайте там только сокет и верните данные в открытую переменную.
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();
}