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();

【讨论】:

我会尝试一下,然后会回复你。此外,服务器当前是同步服务器。是好的还是应该是异步的? 您没有调用networkCodeStart() 方法。您调用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 中的简单套接字服务器的主要内容,如果未能解决你的问题,请参考以下文章

Bash 中的简单套接字服务器?

cSharp中的套接字编程简单示例

Unity 如何连接基于 Node.js 的 Secure WebSocket?

在 Unity 中使用 Android Studio 上的类

C语言中的套接字通信。发送文件内容

什么是从 unity3d 发送 json