【问题标题】:ZeroMQ doesn't work in Unity, but works as console applicationZeroMQ 在 Unity 中不起作用,但可以作为控制台应用程序使用
【发布时间】:2020-12-09 04:15:41
【问题描述】:

我尝试通过 ZeroMQ 将我的 python 进程与 Unity 游戏连接起来。我有一个 python 脚本server.py,它通过对套接字发送消息

import zmq

context = zmq.Context()
socket = context.socket(zmq.PAIR)
socket.bind(f"tcp://*:5556")

socket.send(b"Server message to client")
print("Sent")

我有一个 MonoBehaviour 脚本附加到 Unity 中的游戏对象,如下所示:

public class AiManager : MonoBehaviour
{
    void Start()
    {
        using (var server = new PairSocket())
        {
            server.Connect("tcp://localhost:5556");
            var msg = server.ReceiveFrameString();
            Debug.Log(msg);
        }
    }
}

游戏永远挂在ReceiveFrameString() 上并导致 Unity 崩溃。 server.py 也挂起并且不发送消息。

但是我创建了一个独立的控制台应用程序,代码完全相同:

class Program
{
    static void Main(string[] args)
    {
        using (var server = new PairSocket())
        {
            server.Connect("tcp://localhost:5556");
            var msg = server.ReceiveFrameString();
            Console.WriteLine($"From Server: {msg}");
        }
    }
}

此应用程序完美运行。

我该如何解决这个问题?

【问题讨论】:

  • 您的意思是该方法阻塞的时间比您预期的要长,还是您根本没想到它会阻塞?
  • 该方法永远阻塞(5 分钟以上,直到我手动终止进程),而控制台应用程序立即工作
  • 在接收之前尝试发送消息。建立连接后,服务器通常不会发回消息。您必须至少在收到回复之前发送退货。
  • @jdweng 它有效!在从服务器发送到客户端之前从客户端发送到服务器以某种方式解决了问题。如果您能在答案中解释它为什么有效以及为什么在控制台应用程序中不需要它,我将很高兴接受它
  • 一般来说,与控制台应用程序的一个巨大区别是,在控制台中,您不关心线程是否会冻结一段时间,直到有响应......在 Unity 中,基于框架的应用程序也会冻结你的主线程和整个 Unity 编辑器,直到有响应 -> 使用线程或任务

标签: python c# unity3d zeromq


【解决方案1】:

它可以是一个完整的 PITA,确保 Unity(即 Unity 应用程序)仅具有在本地通话的权限。

我假设您使用的是 PC,而不是 Mac,请仔细检查 Unity 是否允许进行此类网络连接。

Windows 防火墙设置可以是 Unity 的总 PITA。

阅读各种线程,https://forum.unity.com/threads/solved-multiplayer-networking-lan-wont-connect-from-another-pc.470459/

一个解决方案是,在 AWS 上启动一个真正的远程服务器,然后尝试一下!这通常比让 localhost 工作更容易。

一个糟糕的问题是,在某些版本的 Windows 上,愚蠢的“确定”对话框实际上出现在 Unity 后面,这很简单,可以浪费几个小时。

【讨论】:

    【解决方案2】:

    好的,经过几个小时的试验和浏览互联网后,我已经解决了这个问题。

    感谢@jdweng 的评论,要做的第一件事是首先从客户端向服务器发送消息。

    建立连接时服务器不做任何事情。服务器是从机,等待客户端发送命令。 [...] 它与控制台应用程序的行为不同,因为您正在处理具有不同驱动程序的不同内核/操作系统。

    server.SendFrameEmpty(); 添加到客户端并添加socket.recv() 到服务器可以解决问题,但 Unity 仍然冻结。

    我发现this answer 说:

    关键是在开始之前有AsyncIO.ForceDotNet.Force();,在结束之前有NetMQConfig.Cleanup();

    最后整个工作代码是这样的

    public class AiManager : MonoBehaviour
    {
        void Start()
        {
            AsyncIO.ForceDotNet.Force();
            using (var server = new PairSocket())
            {
                server.Connect("tcp://localhost:5556");
                server.SendFrameEmpty();
                var msg = server.ReceiveFrameString();
                Debug.Log(msg);
            }
            NetMQConfig.Cleanup();
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-05-15
      • 1970-01-01
      • 2014-04-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-11-03
      相关资源
      最近更新 更多