Data transmission from Unity (C#) to Python and vice versa using TCP sockets

337 Views Asked by At

So I am relatively new to Unity and socket communications. I have a unity scene from which I want to send some robot position (Vector3) and some other float data to python over tcp socket. I also want to send some control actions (float data) from python to Unity.

On python side I have:

import socket
import time

class connect_class(object):
    
    host = "127.0.0.1"
    port = 25001
    sock = []

    def connect(self):
        self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        try:
            self.sock.connect((self.host, self.port))
        except Exception: 
            print("Connection Error, Check if Unity scene is running.")

class communication_class(object):
    connect_cl = connect_class()
    connect_cl.connect()
    sock = connect_cl.sock

    def receive(self):
        self.receivedData = self.sock.recv(1024).decode("UTF-8") 
        print(self.receivedData)

cl = communication_class()
cl.receive()

The result I am getting is: When I call the receive() for the first time.

{"robot_pos":[{"x":-7.992547035217285,"y":21.728967666625978,"z":-23.946182250976564}]}

However If I call receive() multiple times after that, the same data is just aggregated, as shown below.

{"robot_pos":[{"x":-7.992547035217285,"y":21.728967666625978,"z":-23.946182250976564}]} {"robot_pos":[{"x":-7.992547035217285,"y":21.728967666625978,"z":-23.946182250976564}]} {"robot_pos":[{"x":-7.992547035217285,"y":21.728967666625978,"z":-23.946182250976564}]} {"robot_pos":[{"x":-7.992547035217285,"y":21.728967666625978,"z":-23.946182250976564}]} {"robot_pos":[{"x":-7.992547035217285,"y":21.728967666625978,"z":-23.946182250976564}]} {"robot_pos":[{"x":-7.992547035217285,"y":21.728967666625978,"z":-23.946182250976564}]} {"robot_pos":[{"x":-7.992547035217285,"y":21.728967666625978,"z":-23.946182250976564}]} {"robot_pos":[{"x":-7.992547035217285,"y":21.728967666625978,"z":-23.946182250976564}]} {"robot_pos":[{"x":-7.992547035217285,"y":21.728967666625978,"z":-23.946182250976564}]} {"robot_pos":[{"x":-7.992547035217285,"y":21.728967666625978,"z":-23.946182250976564}]} {"robot_pos":[{"x":-7.992547035217285,"y":21.728967666625978,"z":-23.946182250976564}]} {"robot_pos":[{"x":-7.992547035217285,"y":21.72896766662

I would like to receive only the complete vector only once whenever I call receive.

On the Unity (C#) side I have:

using System.Collections;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Text;
using UnityEngine;
using System.Threading;
using System.IO;

public class comm : MonoBehaviour
{
    Thread mThread;
    public string connectionIP = "127.0.0.1";
    public int connectionPort = 25001;
    IPAddress localAdd;
    TcpListener listener;
    TcpClient client;
    Vector3 receivedPos = Vector3.zero;
    public GameObject robot;
    public Vector3 robot_pos;

    

    bool running;

    public string SaveToString()
    {
        return JsonUtility.ToJson(this);
    }

    public class JsonData
    {
        public List<Vector3> robot_pos = new List<Vector3>();
    }

    private void Update()
    {
        transform.position = receivedPos; //assigning receivedPos in SendAndReceiveData()
        robot_pos = robot.transform.position;

    }

    private void Start()
    {
        robot = GameObject.Find("robot");
        ThreadStart ts = new ThreadStart(GetInfo);
        mThread = new Thread(ts);
        mThread.Start();
    }

    void GetInfo()
    {
        localAdd = IPAddress.Parse(connectionIP);
        listener = new TcpListener(IPAddress.Any, connectionPort);
        listener.Start();

        client = listener.AcceptTcpClient();

        running = true;
        while (running)
        {
            SendData();
            //SendAndReceiveData();
        }
        listener.Stop();
    }

    void SendData()
    {   
        
        NetworkStream nwStream = client.GetStream();
        StreamWriter sw = new StreamWriter(nwStream) { AutoFlush = true };
        var testData = new JsonData();
        testData.robot_pos = new List<Vector3>()
        {
            robot_pos
        };
        var result = JsonUtility.ToJson(testData);

        //---Sending Data to Host----
        sw.WriteLine(result);
        //string data = robot_pos.ToString();
        //sw.Write(data, 0, data.Length);

    }
}

I am not sure how to just receive complete current robot position once per receive() call.

I would appreciate any help or if there are any other better ways to do it.

I tried to use streamwriter.flush() however it also dosent work.

1

There are 1 best solutions below

0
Louis Ingenthron On

Looks like your issue is here:

while (running)
{
    SendData();
    //SendAndReceiveData();
}

That's just going to send the same data in a loop forever.

If you only want it to send the position once when the listener connects, then drop the while loop and just SendData once and then close the socket and wait for another connection.