繁体   English   中英

如何使用 TCP 在两个 Unity 应用程序之间进行通信?

[英]How to communicate between two Unity apps with TCP?

更新

我想出了问题所在。 我试图通过 TCP 移动太多数据,这导致了冻结。 出于某种原因,这并没有在编辑器中体现出来……谁知道是什么原因。 如果其他人偶然发现了这个问题(在像 Unity 这样的程序中,函数不断循环并且数据总是被处理),请考虑您移动了太多不相关的数据。

原帖

我遇到了相当大的问题,我希望我能得到一些指导。

简而言之,我想知道如何使用 TCP 在同一台计算机上与两个 Unity 应用程序进行通信。 我已经让它在编辑器中运行了,但是当两个应用程序都被构建时,沟通很快就会中断。

这真的让我很难过,因为我不明白为什么一个应用程序可以在编辑器环境中运行,而不能在正式版本中运行。

当我使用 TCP 在两个 Unity 应用程序(在同一台计算机上)之间进行通信时,只要其中一个应用程序保留在 Unity 环境中,它就可以工作。 也就是说,如果我构建一个应用程序,然后在 Unity 编辑器中打开另一个应用程序,TCP 通信将完美无缺。

以下是更多背景信息:我的一个应用程序用作用户界面,另一个应用程序与窥镜交互以提供游戏中对象的全息显示。 最初,它们被合并到一个应用程序中 - 但我在让 Unity 的多显示器支持在不同分辨率的两台显示器之间运行时遇到了很多麻烦。 窥镜工厂甚至提供了一个预制件来做到这一点,但它在当前的 SDK 中被破坏了。 所以我求助于使用套接字来连接两个应用程序,每个应用程序一个。

我正在使用 C# 的 TCP 侦听器类: https : //docs.microsoft.com/en-us/dotnet/api/system.net.sockets.tcplistener?view=netframework-4.8

和 TCP 客户端类: https : //docs.microsoft.com/en-us/dotnet/api/system.net.sockets.tcpclient?view=netframework-4.8

目前,UI 充当 TCPListener,生成全息图的应用程序是 TCPClient。 在这些应用程序中的每一个中,我使用了两个队列——一个传入消息队列和一个传出消息队列——它们是主线程和网络线程之间共享的全局变量。

TCP监听器:

private void Start()
{
    incomingMessages = new Queue();
    outgoingMessages = new Queue();

    Application.runInBackground = true;
    thread = new Thread(new ThreadStart(Receive));
    thread.Start();

    //stuff happens that's irrelevant to this question.  And then...   
}

void Receive()
{
    TcpListener server = null;

    try
    {
        // Set the TcpListener on port 13000.
        Int32 port = 13000;
        IPAddress localAddr = IPAddress.Parse("127.0.0.1");

        // TcpListener server = new TcpListener(port);
        server = new TcpListener(localAddr, port);

        // Start listening for client requests.
        server.Start();

        // Buffer for reading data
        Byte[] bytes = new Byte[256];
        String data = null;

        // Enter the listening loop.

        Debug.Log("About to reenter main while in Server...");

        while (threadContinue)
        {
            Debug.Log("Waiting for a connection... ");

            // Perform a blocking call to accept requests.
            // You could also user server.AcceptSocket() here.

            TcpClient client = server.AcceptTcpClient();
            Debug.Log("Connected!");

            data = null;

            // Get a stream object for reading and writing
            NetworkStream stream = client.GetStream();

            int i;

            // Loop to receive all the data sent by the client.
            while ((i = stream.Read(bytes, 0, bytes.Length)) != 0)
            {
                // Translate data bytes to a ASCII string.
                data = System.Text.Encoding.ASCII.GetString(bytes, 0, i);
                Debug.Log("Received from Client: " + data);

                lock (this)

                incomingMessages.Enqueue(data);

                string response = supplyData();
                byte[] msg = System.Text.Encoding.ASCII.GetBytes(response);
                // Send back a response.
                stream.Write(msg, 0, msg.Length);
                Debug.Log("Sent to Client: " + response);
            }

            // Shutdown and end connection
            client.Close();  
        }
    }


    catch (SocketException e)
    {
        Debug.Log("SocketException: ");
        Debug.Log(e);
    }
    finally
    {
        // Stop listening for new clients.
        server.Stop();
    }
        Debug.Log("Exiting 'Receive'");
}

这是 TCP 客户端。 它尝试定期连接,并且在有新数据可用时也尝试连接。 这是为了它可以定期从服务器接收信息并在可用时共享新数据:

void Start()
{
    //prepare networking
    Application.runInBackground = true;

    outgoingMessages = new Queue();
    incomingMessages = new Queue();

    thread = new Thread(new ThreadStart(Connect));
    thread.Start();

    //stuff happens that's irrelevant to this question...
}

private void Connect()
{
    String server = "127.0.0.1";
    Int32 port = 13000;
    string message = "";
    while (threadContinue == true)
    {
        if (timeToConnect())
        {
            lastConnection = ourTime;
            if (outgoingMessages.Count > 0)
                message = outgoingMessages.Dequeue().ToString();
            else
                message = "Nothing to report.";

            try
            {
                // Create a TcpClient.
                // Note, for this client to work you need to have a TcpServer 
                // connected to the same address as specified by the server, port
                // combination.

                client = new TcpClient(server, port);

                // Translate the passed message into ASCII and store it as a Byte array.
                Byte[] data = System.Text.Encoding.ASCII.GetBytes(message);

                // Get a client stream for reading and writing.
                //  Stream stream = client.GetStream();

                stream = client.GetStream();

                // Send the message to the connected TcpServer. 
                stream.Write(data, 0, data.Length);

                Debug.Log("Sent to Server: " + message);


                // Buffer to store the response bytes.
                data = new Byte[256];

                // String to store the response ASCII representation.
                String responseData = String.Empty;

                // Read the first batch of the TcpServer response bytes.
                Int32 bytes = stream.Read(data, 0, data.Length);
                responseData = System.Text.Encoding.ASCII.GetString(data, 0, bytes);

                lock (this)

                    incomingMessages.Enqueue(responseData);

                Debug.Log("Received from Server: " + responseData);


                stream.Close();
                client.Close();

            }
            catch (ArgumentNullException e)
            {
                Debug.Log("ArgumentNullException: ");
                Debug.Log(e);

                outgoingMessages.Enqueue(message);
            }
            catch (SocketException e)
            {
                Debug.Log("SocketException: ");
                Debug.Log(e);
                outgoingMessages.Enqueue(message);
            }
        }
    }
}


private bool timeToConnect()
{
    if ((ourTime - lastConnection > NETWORK_DELAY) || (outgoingMessages.Count > 0))
        return true;
    return false;
}

在单独的线程中实例化,以便 Unity 的主线程可以不受阻碍地继续。

再次 - 它在编辑器中工作,但是当我构建它时,它坏了。

更新

我想出了问题所在。 我试图通过 TCP 移动太多数据,这导致了冻结。 出于某种原因,这并没有在编辑器中表现出来……只是在导出的应用程序中。 谁知道是什么原因。 如果其他人偶然发现了这个问题……您通过构建多个通过网络进行通信的应用程序来绕过 Unity 的多显示器功能……考虑到您的队列负担过多的数据。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM