0

So I want to send and receive from/to Unity and Python in the same run. I have the following components for the communication.

  1. TCPSendPipe - Sends data from Unity to Python
  2. TCPListePipe - Receives data from Python
  3. Python Script - Send (uses socket.connect) and Receive (uses socket.bind)

At the moment I can only use one at a time either, TCPSendPipe with Python receive or, TCPListenPipe with Python send

Following are the scripts:

  • TCPSendPipe.cs
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Net.Sockets;
using UnityEngine;


public class TCPSendPipe : MonoBehaviour
{
    public String Host = "localhost";
    public Int32 Port = 55000;

    TcpClient mySocket = null;
    NetworkStream theStream = null;
    StreamWriter theWriter = null;

    public GameObject robot;
    public Vector3 robPos;


    // Start is called before the first frame update
    void Start()
    {
        robot = GameObject.Find("robot");
        mySocket = new TcpClient();

        if (SetupSocket())
        {
            Debug.Log("socket is set up");
        }
    }

    // Update is called once per frame
    void Update()
    {
        robPos = robot.transform.position; 
        Debug.Log(robPos);
        if (!mySocket.Connected)
        {
            SetupSocket();
        }
        sendMsg();
    }

    public void sendMsg()
    {
        theStream = mySocket.GetStream();
        theWriter = new StreamWriter(theStream);
        //Byte[] sendBytes = System.Text.Encoding.UTF8.GetBytes("yah!! it works");
        Byte[] sendBytes = procData();
        mySocket.GetStream().Write(sendBytes, 0, sendBytes.Length);
    }

    public bool SetupSocket()
    {
        try
        {
            mySocket.Connect(Host, Port);
            Debug.Log("socket is sent");
            return true;
        }
        catch (Exception e)
        {
            Debug.Log("Socket error: " + e);
            return false;
        }
    }

    public Byte[] procData()
    {
        Byte[] bytes = new Byte[12]; // 4 bytes per float
 
        Buffer.BlockCopy( BitConverter.GetBytes( robPos.x ), 0, bytes, 0, 4 );
        Buffer.BlockCopy( BitConverter.GetBytes( robPos.y ), 0, bytes, 4, 4 );
        Buffer.BlockCopy( BitConverter.GetBytes( robPos.z ), 0, bytes, 8, 4 );
        return bytes;
    }

    private void OnApplicationQuit()
    {
        if (mySocket != null && mySocket.Connected)
            mySocket.Close();
    }
}

  • TCPListenPipe.cs
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Text;
using System.Globalization;
using System.Net.Sockets;
using UnityEngine;


public class TCPListenPipe : MonoBehaviour
{
    public String Host = "localhost";
    public Int32 Port = 55000;
    IPAddress localAddr = IPAddress.Parse("127.0.0.1");


    private TcpListener listener = null;
    private TcpClient client = null;
    private NetworkStream ns = null;
    string msg;

    // Start is called before the first frame update
    void Awake()
    {
        listener = new TcpListener(localAddr, Port);
        listener.Start();
        Debug.Log("is listening");

        if (listener.Pending())
        {
        client = listener.AcceptTcpClient();
        Debug.Log("Connected");
        }
    }

    // Update is called once per frame
    void Update()
    {
        if (client == null)
        {
        if (listener.Pending())
        {
            client = listener.AcceptTcpClient();
            Debug.Log("Connected");
        }
        else
        {
            return;
        }
        }

        ns = client.GetStream();

        if ((ns != null) && (ns.DataAvailable))
        {
        StreamReader reader = new StreamReader(ns);
        msg = reader.ReadToEnd();
        float data = float.Parse(msg, CultureInfo.InvariantCulture);       
        Debug.Log(data);
        }
    }

    private void OnApplicationQuit()
    {
        if (listener != null)
        listener.Stop();
    }
}
  • Python Script
import socket
import struct
import numpy as np


class comm(object):

    TCP_IP = '127.0.0.1'
    TCP_PORT = 55000
    BUFFER_SIZE = 12  # Normally 1024, but we want fast response
    conn = []
    addr = []
    s = []

    def connect(self):
        self.s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.s.bind((self.TCP_IP, self.TCP_PORT))
        self.s.listen(1)
        self.conn, self.addr = self.s.accept()
        print ('Connection address:', self.addr)
    

    def receive(self):

        byte_data = self.conn.recv(self.BUFFER_SIZE)
        pos_data = np.array(np.frombuffer(byte_data, dtype=np.float32));
        #print("bytes data:", byte_data)
        print ("received data:", pos_data)
        #conn.close()
        return(pos_data)
    
    def send(self):
        cable_length = 25.123
        MESSAGE = str(cable_length)
        #MESSAGE = cable_length.tobytes()
        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        s.connect((self.TCP_IP, self.TCP_PORT))
        #s.send(MESSAGE)
        s.send(MESSAGE.encode())
        s.close()
        return(MESSAGE)

So in order to send data from Unity to Python, I attach the TCPSendPipe.cs to the scene and within python script I just call receive after connecting.

comm_cl = comm()
comm_cl.connect()
while True:
    data = comm_cl.receive()

Whereas to send data from Python to Unity, I have to detach TCPSendPipe.cs and attach TCPListenPipe.cs to the scene and within python script I just call send (without connect since connect has socket.bind).

send_data = aa.send()

My purpose is to have a 2 way communication between Unity and Python. Can I use 2 different sockets to send and receive?, Is it even possible to create and connect to 2 different sockets at the same time? Any suggestions or ideas on achieveing this is greatly appreciated.

Thank You.

Can I use 2 different sockets to send and receive?, Is it even possible to create and connect to 2 different sockets at the same time?

Rohit
  • 11
  • 1
  • 1
    TCP already supports two way communication .. why open different sockets? You could just stick to one single connection (`TcpClient`) and let both scripts use it. It is possible yes since the two `TcpClient` would just use two different local ports and connect to the same server port. I don't really think it makes sense though. You could have a single connection with a sender and a receiver thread, otherwise your python server would need to differentiate between who is a sending and who is a receiving connection and pass data between them ... – derHugo Feb 17 '23 at 08:52
  • In general you want to go asynchronous with this .. otherwise you will get uncanny app freezes while the sockets are busy – derHugo Feb 17 '23 at 08:59
  • Oh I just saw one of your sockets is a `TcpListener` .. I think you misunderstood the concepts .. this basically opens a new server other clients can connect to => no this is of course not possible since only one TCP socket can use a port at a time. As said you rather want to stick to one `TcpClient` connect it to your python server and channel forth and back communication through it .. just do not close the connection until your app is closed – derHugo Feb 17 '23 at 09:01
  • @derHugo So If I got it right you are saying I should have a single c# script in Unity for the communication and have both sending and receiving functionality defined in that so that they can also share the socket object, right? BTW I quickly tried the 2 different port approach, and it works fine, but as you said if the sockets are buys it might lead to some issues. I will give a try to make a single c# script now and see if it resolves the issue. Thank you for your comment. – Rohit Feb 17 '23 at 09:04

0 Answers0