title: C# - Multithreaded TCP Server/Client
body: <p>I am trying to understand the correct way of how should I make good multithreaded TCP server. </p>
  
  <p>Here is what I have so far:</p>
  
  <pre><code>public class WorldServer
      {
  
          public List&lt;ServerClient&gt; clients = new List&lt;ServerClient&gt;();
  
  
          public int port = 8080;
          public TcpListener server;
          private bool serverStarted;
  
          private int connectionIncrementor;
  
          private MySQLConnection mySQLConnection = new MySQLConnection();
          private MySqlConnection mysqlConn = null;
  
          static void Main(string[] args)
          {
              WorldServer serverInstance = new WorldServer();
              Console.WriteLine("Starting World Server...");
  
              try
              {
                  serverInstance.mysqlConn = new MySqlConnection(serverInstance.mySQLConnection.mysqlConnectionString);
                  serverInstance.mysqlConn.Open();
                  Console.WriteLine("Connected to MySQL version: " + serverInstance.mysqlConn.ServerVersion + "\n");
              }
              catch (Exception e)
              {
                  Console.WriteLine("MySQL Error: " + e.ToString());
              }
              finally
              {
                  if (serverInstance.mysqlConn != null)
                  {
                      serverInstance.mysqlConn.Close();
                  }
              }
  
              serverInstance.clients = new List&lt;ServerClient&gt;();
  
              try
              {
                  serverInstance.server = new TcpListener(IPAddress.Any, serverInstance.port);
                  serverInstance.server.Start();
  
                  serverInstance.StartListening();
  
                  serverInstance.serverStarted = true;
  
                  Console.WriteLine("Server has been started on port: " + serverInstance.port);
              }
              catch (Exception e)
              {
                  Console.WriteLine("Socket error: " + e.Message);
              }
  
              while (true)
              {
                  serverInstance.Update();
              }
  
          }
  
  
          private void Update()
          {
              //Console.WriteLine("Call");
              if (!serverStarted)
              {
                  return;
              }
  
              foreach (ServerClient c in clients.ToList())
              {
                  //Check if TCP is not null
                  if (c.tcp == null)
                      return;
  
                  // Is the client still connected?
                  if (!IsConnected(c.tcp))
                  {
                      c.tcp.Close();
                      clients.Remove(c);
                      Console.WriteLine(c.connectionId + " has disconnected.");
                      continue;
                      //Console.WriteLine("Check for connection?\n");
                  }
                  else
                  {
                      // Check for message from Client.
                      NetworkStream s = c.tcp.GetStream();
                      if (s.DataAvailable)
                      {
                          string data = c.streamReader.ReadLine();
  
                          if (data != null)
                          {
                              if (ValidateJSON(data))
                              {
                                  Thread incomingData = new Thread(() =&gt; OnIncomingData(c, data));
                                  incomingData.Start();
                              }
                          }
  
                      }
                      //continue;
                  }
              }
  
  
  
          }
  
          public bool ValidateJSON(string s)
          {
              try
              {
                  JToken.Parse(s);
                  return true;
              }
              catch (JsonReaderException ex)
              {
                  Trace.WriteLine(ex);
                  return false;
              }
          }
  
          private void OnIncomingData(ServerClient c, string data)
          {
              dynamic json = JsonConvert.DeserializeObject(data);
  
              string header = json.header;
              //Console.WriteLine("HEADER ID:" + json.header);
  
              string connId = json.connectionId;
              int.TryParse(connId, out int connectionId);
  
              int characterId = 0;
              Dictionary&lt;string, string&gt; receivedData = new Dictionary&lt;string, string&gt;();
  
              if (json.data != null)
              {
                  receivedData = json.data.ToObject&lt;Dictionary&lt;string, string&gt;&gt;();
              }
  
  
              if (json.data["characterId"] != null)
              {
                  characterId = json.data["characterId"];
              }
  
              string prefix = header.Substring(0, 2);
              if (prefix != "1x")
              {
                  Console.WriteLine("Unknown packet: " + data + "\n");
              }
              else
              {
                  string HeaderPacket = header.Substring(2);
                  switch (HeaderPacket)
                  {
                      default:
                          Console.WriteLine("Unknown packet: " + data + "\n");
                          break;
                      case "004":
                          Console.WriteLine("Test Packet"); ;
                          break;
                  }
              }
  
  
              //Broadcast(null, data, clients);
              //Console.WriteLine(c.clientName + " has sent the following message :" + data);
          }
  
  
          public bool IsConnected(TcpClient c)
          {
              try
              {
                  if (c != null &amp;&amp; c.Client != null &amp;&amp; c.Client.Connected)
                  {
                      if (c.Client.Poll(0, SelectMode.SelectRead))
                      {
                          return !(c.Client.Receive(new byte[1], SocketFlags.Peek) == 0);
                      }
  
                      return true;
                  }
                  else
                  {
                      return false;
                  }
              }
              catch
              {
                  return false;
              }
          }
  
          private void StartListening()
          {
              server.BeginAcceptTcpClient(OnConnection, server);
          }
  
          private void OnConnection(IAsyncResult ar)
          {
              connectionIncrementor++;
              TcpListener listener = (TcpListener)ar.AsyncState;
              clients.Add(new ServerClient(listener.EndAcceptTcpClient(ar)));
              clients[clients.Count - 1].connectionId = connectionIncrementor;
              StartListening();
  
  
              //Send a message to everyone, say someone has connected!
              Dictionary&lt;string, object&gt; SendDataBroadcast = new Dictionary&lt;string, object&gt;();
              SendDataBroadcast.Add("connectionId", clients[clients.Count - 1].connectionId);
  
              Broadcast("001", SendDataBroadcast, clients[clients.Count - 1].connectionId);
              Console.WriteLine(clients[clients.Count - 1].connectionId + " has connected.");
          }
  
          public void Broadcast(string header, Dictionary&lt;string, object&gt; data, int cnnId = 0)
          {
              string jsonData = JsonConvert.SerializeObject(data, Formatting.Indented);
  
              foreach (ServerClient c in clients)
              {
                  try
                  {
                      if (header == null)
                      {
                          header = "000";
                      }
                      JsonData SendData = new JsonData();
                      SendData.header = "0x" + header;
                      SendData.data = JObject.Parse(jsonData);
                      SendData.connectionId = cnnId;
                      string JSonData = JsonConvert.SerializeObject(SendData);
                      //Console.WriteLine("SENDING: " + JSonData);
                      c.streamWriter.WriteLine(JSonData);
                      c.streamWriter.Flush();
                  }
                  catch (Exception e)
                  {
                      Console.WriteLine("Write error : " + e.Message + " to client " + c.connectionId);
                  }
              }
          }
  
  
          public void Send(string header, Dictionary&lt;string, object&gt; data, int cnnId)
          {
              string jsonData = JsonConvert.SerializeObject(data, Formatting.Indented);
  
              foreach (ServerClient c in clients.ToList())
              {
  
                  if (c.connectionId == cnnId)
                  {
                      try
                      {
                          //Console.WriteLine("Sending...");
                          if (header == null)
                          {
                              header = "000";
                          }
                          JsonData SendData = new JsonData();
                          SendData.header = "0x" + header;
                          SendData.data = JObject.Parse(jsonData);
                          SendData.connectionId = cnnId;
  
                          string JSonData = JsonConvert.SerializeObject(SendData);
  
                          c.streamWriter.WriteLine(JSonData);
                          c.streamWriter.Flush();
                          //Console.WriteLine("Trying to send data to connection id: " + cnnId + " data:" + sendData);
                      }
                      catch (Exception e)
                      {
                          Console.WriteLine("Write error : " + e.Message + " to client " + c.connectionId);
                      }
                  }
              }
          }
      }
  
      public class ServerClient
      {
          public TcpClient tcp;
          public StreamReader streamReader;
          public StreamWriter streamWriter;
          public int accountId;
          public int connectionId;
          public ServerClient(TcpClient clientSocket)
          {
              tcp = clientSocket;
              streamReader = new StreamReader(tcp.GetStream(), false);
              streamWriter = new StreamWriter(tcp.GetStream());
              clientSocket.NoDelay = true;
          }
      }
  </code></pre>
  
  <p>The TCP server works. However I am really not sure if this is the best approach I can take.</p>
  
  <ol>
  <li>Have I made the multi-threading well ? Probably not. I would like to receive advices where i can make it better.</li>
  <li>Do I need to create a new thread on every <code>OnIncomingData</code> ?</li>
  <li>Do I need to create new thread on every <code>Send</code> and <code>Broadcast</code> ?</li>
  <li>Very often I receive error here <code>foreach (ServerClient c in clients.ToList())</code>. What can be the cause of it ? </li>
  <li>What parts of the client is good to be multithreaded also aka the listening function for incoming data or the sending functions?</li>
  <li>All advices are most welcome!</li>
  </ol>