title: How to communicate between two Unity apps with TCP?
body: <p><strong>Update</strong></p>
  
  <p>I figured out what the problem was.  I was trying to move too much data over TCP, and it was causing freeze-ups.  For some reason, this wasn't manifesting in the editor...who knows for what reason.  If anyone else stumbles upon this problem (in a program like Unity, where functions are looping constantly and data is always being processed), consider that you're moving too much irrelevant data.</p>
  
  <p><strong>Original Post</strong></p>
  
  <p>I've run into quite the problem, and I'm hoping I can receive some guidance.</p>
  
  <p>In short, I'm wondering how to use TCP to communicate two Unity apps over the same computer.  I've gotten it functioning in editor, but when both apps are built, communication quickly breaks down.</p>
  
  <p>This is really stumping me, because I don't understand why an app would work in the Editor environment, but not in the official build.</p>
  
  <p>When I use TCP to communicate between two Unity apps (on the same computer), it works so long as one of them is kept in the Unity environment.  That is, if I build one app, and open the other in the Unity editor, TCP communication works flawlessly.</p>
  
  <p>Here is some more background:  One of my apps is functioning as a User Interface, and the other is interfacing with a Looking Glass to provide a holographic display of in-game objects.  Originally, they were combined into one App - but I had a lot of trouble getting Unity's multidisplay support to function between two monitors of different resolutions.  Looking Glass factory even provides a prefab to do just this, but it is broken in the current SDK.  So I have resorted to using sockets to interface between two apps, one for each monitor.</p>
  
  <p>I'm using C#'s TCP listener class: <a href="https://docs.microsoft.com/en-us/dotnet/api/system.net.sockets.tcplistener?view=netframework-4.8" rel="nofollow noreferrer">https://docs.microsoft.com/en-us/dotnet/api/system.net.sockets.tcplistener?view=netframework-4.8</a></p>
  
  <p>And TCP client class: <a href="https://docs.microsoft.com/en-us/dotnet/api/system.net.sockets.tcpclient?view=netframework-4.8" rel="nofollow noreferrer">https://docs.microsoft.com/en-us/dotnet/api/system.net.sockets.tcpclient?view=netframework-4.8</a></p>
  
  <p>Presently, the UI is acting as the TCPListener, and the application that produces holograms is the TCPClient.  Within each of these applications, I'm using two Queues - an IncomingMessages queue and an Outgoing Messages queue - which are global variables shared between the main thread and the networking thread.</p>
  
  <p>TCP Listener:</p>
  
  <pre><code>private void Start()
  {
      incomingMessages = new Queue();
      outgoingMessages = new Queue();
  
      Application.runInBackground = true;
      thread = new Thread(new ThreadStart(Receive));
      thread.Start();
  
      //stuff happens that's irrelevant to this question.  And then...   
  }
  
  void Receive()
  {
      TcpListener server = null;
  
      try
      {
          // Set the TcpListener on port 13000.
          Int32 port = 13000;
          IPAddress localAddr = IPAddress.Parse("127.0.0.1");
  
          // TcpListener server = new TcpListener(port);
          server = new TcpListener(localAddr, port);
  
          // Start listening for client requests.
          server.Start();
  
          // Buffer for reading data
          Byte[] bytes = new Byte[256];
          String data = null;
  
          // Enter the listening loop.
  
          Debug.Log("About to reenter main while in Server...");
  
          while (threadContinue)
          {
              Debug.Log("Waiting for a connection... ");
  
              // Perform a blocking call to accept requests.
              // You could also user server.AcceptSocket() here.
  
              TcpClient client = server.AcceptTcpClient();
              Debug.Log("Connected!");
  
              data = null;
  
              // Get a stream object for reading and writing
              NetworkStream stream = client.GetStream();
  
              int i;
  
              // Loop to receive all the data sent by the client.
              while ((i = stream.Read(bytes, 0, bytes.Length)) != 0)
              {
                  // Translate data bytes to a ASCII string.
                  data = System.Text.Encoding.ASCII.GetString(bytes, 0, i);
                  Debug.Log("Received from Client: " + data);
  
                  lock (this)
  
                  incomingMessages.Enqueue(data);
  
                  string response = supplyData();
                  byte[] msg = System.Text.Encoding.ASCII.GetBytes(response);
                  // Send back a response.
                  stream.Write(msg, 0, msg.Length);
                  Debug.Log("Sent to Client: " + response);
              }
  
              // Shutdown and end connection
              client.Close();  
          }
      }
  
  
      catch (SocketException e)
      {
          Debug.Log("SocketException: ");
          Debug.Log(e);
      }
      finally
      {
          // Stop listening for new clients.
          server.Stop();
      }
          Debug.Log("Exiting 'Receive'");
  }
  </code></pre>
  
  <p>And here is the TCP Client.  It attempts to connect a regular intervals, and also whenever new data is available.  This is so that it can receive information from the server regularly and share new data whenever it is available:</p>
  
  <pre><code>void Start()
  {
      //prepare networking
      Application.runInBackground = true;
  
      outgoingMessages = new Queue();
      incomingMessages = new Queue();
  
      thread = new Thread(new ThreadStart(Connect));
      thread.Start();
  
      //stuff happens that's irrelevant to this question...
  }
  
  private void Connect()
  {
      String server = "127.0.0.1";
      Int32 port = 13000;
      string message = "";
      while (threadContinue == true)
      {
          if (timeToConnect())
          {
              lastConnection = ourTime;
              if (outgoingMessages.Count &gt; 0)
                  message = outgoingMessages.Dequeue().ToString();
              else
                  message = "Nothing to report.";
  
              try
              {
                  // Create a TcpClient.
                  // Note, for this client to work you need to have a TcpServer 
                  // connected to the same address as specified by the server, port
                  // combination.
  
                  client = new TcpClient(server, port);
  
                  // Translate the passed message into ASCII and store it as a Byte array.
                  Byte[] data = System.Text.Encoding.ASCII.GetBytes(message);
  
                  // Get a client stream for reading and writing.
                  //  Stream stream = client.GetStream();
  
                  stream = client.GetStream();
  
                  // Send the message to the connected TcpServer. 
                  stream.Write(data, 0, data.Length);
  
                  Debug.Log("Sent to Server: " + message);
  
  
                  // Buffer to store the response bytes.
                  data = new Byte[256];
  
                  // String to store the response ASCII representation.
                  String responseData = String.Empty;
  
                  // Read the first batch of the TcpServer response bytes.
                  Int32 bytes = stream.Read(data, 0, data.Length);
                  responseData = System.Text.Encoding.ASCII.GetString(data, 0, bytes);
  
                  lock (this)
  
                      incomingMessages.Enqueue(responseData);
  
                  Debug.Log("Received from Server: " + responseData);
  
  
                  stream.Close();
                  client.Close();
  
              }
              catch (ArgumentNullException e)
              {
                  Debug.Log("ArgumentNullException: ");
                  Debug.Log(e);
  
                  outgoingMessages.Enqueue(message);
              }
              catch (SocketException e)
              {
                  Debug.Log("SocketException: ");
                  Debug.Log(e);
                  outgoingMessages.Enqueue(message);
              }
          }
      }
  }
  
  
  private bool timeToConnect()
  {
      if ((ourTime - lastConnection &gt; NETWORK_DELAY) || (outgoingMessages.Count &gt; 0))
          return true;
      return false;
  }
  </code></pre>
  
  <p>Instantiated in separate threads so that Unity's main thread can continue unhindered.</p>
  
  <p>Again - it works in Editor, but when I build it, it breaks.</p>