TCPClient brainfart

Hi,

I am trying to set ups the basics for TCP/IP communication. I am going to receive messages from a server, and will use the messages to change my Unity3D scene.

I created a TCPListenerBehaviour (which I will be using):

public class TCPListenerBehaviour : MonoBehaviour
{  
    private TcpClient socketConnection;
    private Thread clientReceiveThread;

    public string url = "localhost";
    public int port = 8052;

    void Start()
    {
        ConnectToTcpServer();
    }

    private void ConnectToTcpServer()
    {
        try
        {
            clientReceiveThread = new Thread(new ThreadStart(ListenForData));
            clientReceiveThread.IsBackground = true;
            clientReceiveThread.Start();
        }
        catch (Exception e)
        {
            //
        }
    }
  
    private void ListenForData()
    {
        try
        {
            socketConnection = new TcpClient(url, port);

            Byte[] bytes = new Byte[1024];
            while (true)
            {            
                using (NetworkStream stream = socketConnection.GetStream())
                {
                    int length;

                    while ((length = stream.Read(bytes, 0, bytes.Length)) != 0)
                    {
                        var incomingData = new byte[length];
                        Array.Copy(bytes, 0, incomingData, 0, length);
                     
                        string serverMessage = Encoding.ASCII.GetString(incomingData);
                        Debug.Log("server message received as: " + serverMessage);
                    }
                }
            }
        }
        catch (SocketException socketException)
        {
            //
        }
    }

and I created a TCPSenderBehaviour (which I wanted to use for testing):

public class TCPSenderBehaviour : MonoBehaviour
{  
    private TcpClient socketConnection;

    public string url = "localhost";
    public int port = 8052;

    void Start()
    {
        ConnectToTcpServer();
    }

   void Update()
   {
       if (Input.GetKeyDown(KeyCode.Space))
       {
           SendMessage("Test");
       }
   }

    private void ConnectToTcpServer()
    {
        try
        {
            socketConnection = new TcpClient(url, port);
        }
        catch (Exception e)
        {
            //
        }
    }
  
    public void Send(string message)
    {
        if(socketConnection == null)
        {
            return;
        }

        try
        {      
            NetworkStream stream = socketConnection.GetStream();
            if (stream.CanWrite)
            {         
                byte[] clientMessageAsByteArray = Encoding.ASCII.GetBytes(message);

                stream.Write(clientMessageAsByteArray, 0, clientMessageAsByteArray.Length);
            }
        }
        catch (SocketException socketException)
        {
           //
        }
    }
}

Now, TCPSenderBehaviour does send every time I tap space.
But TCPListenerBehaviour never receives anything?

Where’s the problem?

Well, TCP is a server client architecture. You never even created a TCP server which could accept a client connect request. The TcpClient class, as the name suggests, represents a client connecting to a server. The counterpart would be the TcpListener. It will actually open a listening socket and is waiting for a connection request from a client. When the server does accept the connection an actual logical link is created. The AcceptTcpClient method on the server will return a TcpClient which wraps the socket which the server can use to communicate with that specific client.

Even though this is clearly just a rudimentary test, be warned that TCP is a streaming protocol and not a message based protocol. It provides a bidirectional endless stream for both sides. Data can arrive fragmented but never out of order. It’s a continuous stream of data. If you want to send “messages” you have to manually extract those from the stream.

You may want to have a look at my answer over here and take a look at my example server(.NET standalone app) / client(MonoBehaviour).

Note that a TcpListener has to be bound to a certain address and port. Though usually you bind the server to the special address IPAddress.Any so no matter which IP of your server receives a connection, your server will react. This only matters if your machine has several IP addresses and you want to run serveral servers on the same port on different IP addresses. This may be quite common in the professional field of server administration, your typical internet home connection only has a single public IP address that has to go through your NAT router and splits based on the ports.

Anyways when you create a TcpListener you have to actually “Start” it. This would actually bind the underlying listening socket to the address / port and is able to receive connection requests. Likewise the TcpClient has to call the Connect method with a specific IP and port you want to connect to. Currently you don’t do anything like that ^^. As mentioned, have a look at my example. It uses a very simple application level protocol. I send a single 32 bit integer indicating the length of a message (which is simply an image), followed by exactly that many bytes of data. The BinaryReader directly reads from the networkstream. The networkstream is in blocking mode, so if the reader tries to read more data than what’s available, the stream would block until enough data has arrived. The blocking behaviour makes it very simply to handle the actual data.

1 Like

Thank you, I solved it. Now I am stuck with reading the messages using System.IO.Pipelines: Getting System.IO.Pipelines into Unity