【问题标题】:How to make c# in Unity communicate with Python如何让 Unity 中的 c# 与 Python 通信
【发布时间】:2019-11-26 13:04:39
【问题描述】:

我正在为 Unity 游戏制作 Q-Learning 机器人,该机器人使用 Python,游戏使用 c#,如何让这两个程序交换任何类型的数据(即整数字符串数组等)? 任何让 Python 和 c# 进行 Unity 通信的方法都可以解决我的问题, 我可以将任何内容集成到我的代码中。

我的 Python 版本是 3.6。

【问题讨论】:

    标签: c# python unity3d


    【解决方案1】:

    这是我用来在 unity 和 python 之间进行通信的。来自不同来源/教程的混合。

    (它对我有用,但一个已知的问题是当 python 中出现错误时 Unity 会冻结。我已经编写了一个返回空字节数组的 try/catch 方法,但这似乎不起作用。)

    C# 脚本

    using UnityEngine;
    //using System.Net;
    using System.Net.Sockets;
    using System;
    
    public class SocketFloat : MonoBehaviour
    {
        public string ip = "127.0.0.1";
        public int port = 60000;
        private Socket client;
        [SerializeField]
        private float[] dataOut, dataIn; //debugging
    
        /// <summary>
        /// Helper function for sending and receiving.
        /// </summary>
        /// <param name="dataOut">Data to send</param>
        /// <returns></returns>
        protected float[] ServerRequest(float[] dataOut)
        {
            //print("request");
            this.dataOut = dataOut; //debugging
            this.dataIn = SendAndReceive(dataOut); //debugging
            return this.dataIn;
        }
    
        /// <summary> 
        /// Send data to port, receive data from port.
        /// </summary>
        /// <param name="dataOut">Data to send</param>
        /// <returns></returns>
        private float[] SendAndReceive(float[] dataOut)
        {
            //initialize socket
            float[] floatsReceived;
            client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            client.Connect(ip, port);
            if (!client.Connected) {
                Debug.LogError("Connection Failed");
                return null; 
            }
    
            //convert floats to bytes, send to port
            var byteArray = new byte[dataOut.Length * 4];
            Buffer.BlockCopy(dataOut, 0, byteArray, 0, byteArray.Length);
            client.Send(byteArray);
    
            //allocate and receive bytes
            byte[] bytes = new byte[4000];
            int idxUsedBytes = client.Receive(bytes);
            //print(idxUsedBytes + " new bytes received.");
    
            //convert bytes to floats
            floatsReceived = new float[idxUsedBytes/4];
            Buffer.BlockCopy(bytes, 0, floatsReceived, 0, idxUsedBytes);
    
            client.Close();
            return floatsReceived;
        }
    }
    

    Python 代码

    import socket
    import struct
    import traceback
    import logging
    import time
    
    def sending_and_reciveing():
        s = socket.socket()
        socket.setdefaulttimeout(None)
        print('socket created ')
        port = 60000
        s.bind(('127.0.0.1', port)) #local host
        s.listen(30) #listening for connection for 30 sec?
        print('socket listensing ... ')
        while True:
            try:
                c, addr = s.accept() #when port connected
                bytes_received = c.recv(4000) #received bytes
                array_received = np.frombuffer(bytes_received, dtype=np.float32) #converting into float array
    
                nn_output = return_prediction(array_received) #NN prediction (e.g. model.predict())
    
                bytes_to_send = struct.pack('%sf' % len(nn_output), *nn_output) #converting float to byte
                c.sendall(bytes_to_send) #sending back
                c.close()
            except Exception as e:
                logging.error(traceback.format_exc())
                print("error")
                c.sendall(bytearray([]))
                c.close()
                break
    
    sending_and_reciveing() 
    

    如果您想发出请求,请让您的 Unity 脚本(您正在使用的脚本)派生自 SocketFloat:

    public class Turing : SocketFloat
    

    调用 ServerRequest 从 Python 返回一个预测。

    float[] prediction = ServerRequest(myArray)
    

    【讨论】:

    • s.listen(30) 不会“听 30 秒”。从文档中,该参数“指定系统在拒绝新连接之前将允许的未接受连接的数量”
    【解决方案2】:

    我假设机器人和游戏是独立的并且可能是远程进程。对于双向通信,您可以考虑使用一些消息传递中间件或网络服务。

    我怀疑更大的问题出在 Unity 方面。与大多数专有平台一样,Unity 拥有自己的网络 API。我不确定在 Unity 中使用基于 http 或 tcp 的独立服务有多复杂。

    Unity 文档中的This page 涵盖了与非统一应用程序的集成。如果您想采用 Web 服务方式,Webhooks 将是您的最佳选择。

    RabbitMQ 显然有一个Unity3d client,你也许能找到其他类似的开源项目。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-08-07
      相关资源
      最近更新 更多