Python与Unity之间通信实现【Socket实现】

最近做的项目需要实现Python与Unity之间的数据通信,Unity中也有python的插件如IronPython、PyUnity,但是我的python环境和模型都在WSL2中配置了,就选择了用Socket通信的方法实现。
 

一、Python实现连接和传输

思路就是把一个np二维/一维数组转换为list类型,然后两两数字之间插入","作为分割转换为字符串类型,转换为UTF-8编码的字节流,通过socket发送。

python部分的实现:

import numpy as np
import socket
import os

def connect_unity(host,port):
    global sock
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    # sock = socket.socket()
    sock.connect((host, port))
    print('连接已建立')

def send_to_unity(arr):
    arr_list = arr.flatten().tolist() # numpy数组转换为list类型
    data = '' + ','.join([str(elem) for elem in arr_list]) + ''  # 每个float用,分割
    sock.sendall(bytes(data, encoding="utf-8"))  # 发送数据
    print("向unity发送:", arr_list)

def rec_from_unity():
    data = sock.recv(1024)
    data = str(data, encoding='utf-8')
    data = data.split(',')
    new_data = []
    for d in data:
        new_data.append(float(d))
    print('从环境接收:',new_data)
    return new_data

# 生成随机数据
data = np.random.random(731,71)

host = '127.0.0.1'
port = 5005   

connect_unity(host,port)

for i in range(output_data.shape[0]):
    send_to_unity(output_data[i])
    rec_from_unity()  # Unity接收数据后再发送下一个

二、Unity实现监听和传输

using System;
using System.Collections;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Text;
using UnityEngine;
public class U2P
{
    private static U2P instance;
    private Socket serverSocket;
    private Socket clientSocket;
    public bool isConnected;

    public static U2P Instance
    {
        get
        {
            if(instance == null)
            {
                instance = new U2P();
            }
            return instance;
        }
    }
    private U2P()
    {
        serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        IPAddress ipAddress = IPAddress.Parse("127.0.0.1");
        // IPAddress ipAddress = IPAddress.Parse("0.0.0.0");
        serverSocket.Bind(new IPEndPoint(ipAddress, 5005));  
        serverSocket.Listen(5); 
        StartServer();
    }
    private void StartServer()
    {
        serverSocket.BeginAccept(AcceptCallback, null);
    }
    private void AcceptCallback(IAsyncResult ar)
    {
        Socket sc = serverSocket.EndAccept(ar); 
        if (clientSocket == null)
        {
            clientSocket = sc; 
            isConnected = true;
            Debug.Log("连接成功");
        }
    }
    public float[] RecData()
    {
        try
        {
            if (clientSocket != null)
            {
                int canRead = clientSocket.Available;
                byte[] buff = new byte[canRead];
                clientSocket.Receive(buff);
                string str = Encoding.UTF8.GetString(buff);
                //Debug.Log(str);
                if (str == "")
                {
                    return null;
                }
                //str = str.Replace("[","").Replace("]","").Replace("n")Replace("Replace(
                //Debug.Log(“接受消息:”+ str);
                string[] strData = str.Split(',');
                float[] data = new float[strData.Length];
                for (int i = 0; i < strData.Length; i++)
                {
                    data[i] = float.Parse(strData[i]);
                }
                return data;
            }
        }
        catch (Exception ex)
        {
            Debug.LogError("发生错误:"+ex);
            if (clientSocket != null)
            {
                clientSocket.Close(); 
                clientSocket = null; 
                isConnected = false;
                StartServer();
            }
        }
        return null;
    }
    public void SendData(List<float> data)
    {
        try
        {
            if (clientSocket != null)
            {
                string strData = "";
                for (int i = 0; i < data.Count; i++)
                {
                    strData += data[i];
                    if (i != data.Count - 1)
                    {
                        strData += ",";
                    }
                }
                // 使用clientSocket发送strData到服务器的代码
                byte[] dataBytes = Encoding.UTF8.GetBytes(strData);
                clientSocket.Send(dataBytes);
            }
        }
        catch (Exception ex)
        {
            //Debug.LogError("发生错误:”+ex);
            if (clientSocket != null)
            {
                clientSocket.Close();
                clientSocket = null;
                isConnected = false;
                StartServer();
            }
        }
    }
}

调用上述U2P类的代码,挂在到场景中的一个物体中:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor.Animations;
using UnityEditor;

public class Connect : MonoBehaviour
{
    private void Update()
    {
        if (U2P.Instance.isConnected)
        {
            float[] data = U2P.Instance.RecData();
            if (data != null)
            {
                print(data.Length);
                print("接收到数据");
                U2P.Instance.SendData(new List<float>(){0}); // 返回0,表示接收到数据
                // TODO: 处理数据
            }
        }
    }
}

需要注意的是,由于这种方法是将float类型(4字节)转换为字符串类型,因此一个浮点数如果是10长度,则需要10个字节,但是socket的单次传输是有限制的,如果需要传输很大数据,所以这里使用分多次连续传输,以一次接受到返回0为接受成功。