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为接受成功。