title: Guidance with TCP Client, reconnect function, etc
body: <p>I have a TCP Client that mainly runs on <strong>mono</strong> that I wish some guidance with, I think I am doing some things wrong, something not needed, etc.</p>
  
  <p><strong>The below code is part of what I use to serve as a sample for my doubts.</strong></p>
  
  <ul>
  <li><p>As you can see once the constructor is called, its when I instantiate the ConcurrentQueues, should I have it instantiated by itself not needing to initiate it from the constructor or the way I am currently doing is the correct one or it doesn't really matter ?</p></li>
  <li><p>I currently have 3 threds running which I belive I could reduce to 2 or even one but I am a bit insecured for doing that.</p>
  
  <p>As you can see I have: </p>
  
  <p><code>receiveThread</code> for <code>_ReceivePackets</code>
  This one controls all received data from the roomserver</p>
  
  <p><code>sendThread</code> for <code>_SendPackets</code>
  This one controls everything that must be sent to the roomserver</p>
  
  <p><code>responseThread</code> for <code>_Response</code>
  This will handles all the responses that were queued from the roomserver</p>
  
  <p>I belive I could merge <code>_SendPackets</code> with <code>_ReceivePackets</code> as one and increase to my class <code>SendPackets</code> wether it is a packet to be sent or one that was delivered, what I am afraid of is that if it has a huge in/out if it would still keep up withou messing things up.</p>
  
  <p>I have the <code>_Response</code> separated as it will be processing more of the response data per type of reply which I think is fine and don't think it would work out if I remove it and let the <code>_Response</code> handle it by itself since some packets won't be readed in just one shot.</p></li>
  <li><p>How far should I rely myself into the <code>_socket.Connected</code> ?</p></li>
  <li><p>I am having some issues to deploy a reconnect, most of the time when I have some connection issue, it doesn't trigger any errors it just  sit in there with the ports open as if it still connected, how should I detect if I am still live or not ?</p></li>
  <li><p>Over all recommendations, advices or online free reading materials ?</p></li>
  </ul>
  
  <p>Side note: This is a very basic implementation of a chat tcp client for learning that I am currently working on.</p>
  
  <pre><code>using System;
  using System.IO;
  using System.Net;
  using System.Text;
  using System.Threading;
  using System.Net.Sockets;
  using System.Collections.Concurrent;
  using log4net;
  
  namespace Connection
  {
      public class Roomserver
      {
          private static readonly ILog logger = LogManager.GetLogger(typeof(Roomserver));
  
          private ConcurrentQueue&lt;byte[]&gt; RoomserverReceivedPackets = null;
          private ConcurrentQueue&lt;SendPackets&gt; RoomserverSendPackets = null;
  
          private AutoResetEvent _queueNotifier = new AutoResetEvent(false);
          private AutoResetEvent _sendQueueNotifier = new AutoResetEvent(false);
  
          public static byte[] myinfo = null;
  
          private IPAddress _server = null;
          private int _port = 0;
          private int _roomID = 0;
  
          private Socket _socket;
          private Status _status = Status.Disconnected;
  
          private Thread responseThread = null;
          private Thread receiveThread = null;
          private Thread sendThread = null;
          private EndPoint _roomServer = null;
  
          public bool Connected
          {
              get { return _socket.Connected; }
          }
  
          public Status GetStatus
          {
              get { return _status; }
          }
  
          public Roomserver(IPAddress server, int port)
          {
              this._server = server;
              this._port = port;
  
              RoomserverReceivedPackets = new ConcurrentQueue&lt;byte[]&gt;();
              RoomserverSendPackets = new ConcurrentQueue&lt;SendPackets&gt;();
          }
  
          public Roomserver(IPAddress server, int port, int roomID)
          {
              this._server = server;
              this._port = port;
              this._roomID = roomID;
  
              RoomserverReceivedPackets = new ConcurrentQueue&lt;byte[]&gt;();
              RoomserverSendPackets = new ConcurrentQueue&lt;SendPackets&gt;();
          }
  
          public bool Connect()
          {
              try
              {
                  if (_status != Status.Disconnected)
                      this.Disconnect();
  
                  _socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                  IPEndPoint remoteEndPoint = new IPEndPoint(_server, _port);
  
                  _socket.Connect(remoteEndPoint);
                  _status = Status.Connect;
                  _roomServer = (EndPoint)remoteEndPoint;
  
                  receiveThread = new Thread(_ReceivePackets);
                  receiveThread.Start();
  
                  sendThread = new Thread(_SendPackets);
                  sendThread.Start();
  
                  responseThread = new Thread(_Response);
                  responseThread.Start();
  
                  return _socket.Connected;
              }
              catch (SocketException se)
              {
                  logger.Error("Connect: " + se.ToString());
                  _status = Status.Disconnected;
  
                  return false;
              }
              catch (Exception ex)
              {
                  logger.Error("Connect: " + ex.ToString());
                  _status = Status.Disconnected;
  
                  return false;
              }
          }
  
          public bool Disconnect()
          {
              if (_socket.Connected)
              {
                  _status = Status.Disconnected;
  
                  if (receiveThread != null &amp;&amp; receiveThread.IsAlive)
                  {
                      receiveThread.Abort();
                  }
  
                  if (responseThread != null &amp;&amp; responseThread.IsAlive)
                  {
                      responseThread.Abort();
                  }
  
                  if (sendThread != null &amp;&amp; sendThread.IsAlive)
                  {
                      sendThread.Abort();
                  }
  
                  try
                  {
                      _socket.Close();
                      return true;
                  }
                  catch (Exception ex)
                  {
                      logger.Info("Disconnect " + ex.ToString());
                      _status = Status.Disconnected;
                      return true;
                  }
              }
              else
              {
                  logger.Info("Not connected ...");
                  _status = Status.Disconnected;
                  return true;
              }
          }
  
          public bool SendData(byte[] bytes, bool delay)
          {
              try
              {
                  SendPackets data = new SendPackets()
                  {
                      Data = bytes,
                      Delay = delay
                  };
                  RoomserverSendPackets.Enqueue(data);
                  _sendQueueNotifier.Set();
                  return true;
              }
              catch (Exception ex)
              {
                  logger.Error("SendData " + ex.ToString());
                  return false;
              }
          }
  
          private void _SendPackets()
          {
              while (_socket.Connected)
              {
                  _sendQueueNotifier.WaitOne();
                  while (!RoomserverSendPackets.IsEmpty)
                  {
                      SendPackets packet = null;
                      if (RoomserverSendPackets.TryDequeue(out packet))
                      {
                          try
                          {
                              if (packet.Delay)
                              {
                                  Thread.Sleep(1000);
                                  _socket.Send(packet.Data);
                              }
                              else
                                  _socket.Send(packet.Data);
                          }
                          catch (SocketException soe)
                          {
                              logger.Error(soe.ToString());
                          }
                      }
                  }
              }
          }
  
          private void _ReceivePackets()
          {
              bool extraData = false;
              MemoryStream fullPacket = null;
              int fullPacketSize = 0;
  
              while (_socket.Connected)
              {
                  try
                  {
                      byte[] bytes = new byte[65536];
                      int bytesRead = _socket.ReceiveFrom(bytes, ref _roomServer);
                      int packetSize = 0;
                      int reply = 0;
  
                      byte[] data = new byte[bytesRead];
                      Array.Copy(bytes, data, bytesRead);
  
                      MemoryStream bufferReceived = new MemoryStream(data, 0, data.Length);
                      using (var reader = new BinaryReader(bufferReceived))
                      {
                          packetSize = (int)reader.ReadInt32() + 4;
                          reply = (int)reader.ReadByte();
                      }
  
                      if (!extraData &amp;&amp; packetSize &lt;= bytesRead)
                      {
                          if (data.Length &gt; 0)
                          {
                              RoomserverReceivedPackets.Enqueue(data);
                              _queueNotifier.Set();
                          }
                      }
                      else
                      {
                          if (!extraData)
                          {
                              fullPacket = new MemoryStream(new byte[packetSize], 0, packetSize);
                              fullPacket.Write(data, 0, data.Length);
                              fullPacketSize = data.Length;
                              extraData = true;
                          }
                          else
                          {
                              if (fullPacketSize &lt; fullPacket.Length)
                              {
                                  int left = (int)fullPacket.Length - fullPacketSize;
                                  fullPacket.Write(data, 0, (left &lt; data.Length) ? left : data.Length);
                                  fullPacketSize += (left &lt; data.Length) ? left : data.Length;
  
                                  if (fullPacketSize &gt;= fullPacket.Length)
                                  {
                                      extraData = false;
                                      RoomserverReceivedPackets.Enqueue(fullPacket.ToArray());
                                      _queueNotifier.Set();
                                      fullPacket.Close();
                                  }
                              }
                          }
                      }
                  }
                  catch (SocketException soe)
                  {
                      logger.Error("_ReceivePackets " + soe.ToString());
                  }
                  catch (Exception ex)
                  {
                      logger.Error("_ReceivePackets " + ex.ToString());
                  }
              }
          }
  
          private void _Response()
          {
              while (_socket.Connected)
              {
                  _queueNotifier.WaitOne();
  
                  while (!RoomserverReceivedPackets.IsEmpty)
                  {
                      byte[] data = null;
                      if (RoomserverReceivedPackets.TryDequeue(out data))
                      {
                          MemoryStream bufferReceived = new MemoryStream(data, 0, data.Length);
                          using (var reader = new BinaryReader(bufferReceived))
                          {
                              int packetSize = (int)reader.ReadInt32();
                              byte reply = reader.ReadByte();
  
                              switch (reply)
                              {
                                  case 0x01: // Login request
                                      break;
                                  case 0x02: // Login accepted
                                      break;
                                  case 0x03: // Enter room
                                      break;
                                  case 0x04: // Members list
                                      break;
                                  case 0x05: // Send Chat
                                      break;
                                  case 0x06: // Receive Chat
                                      break;
                                  case 0x07: // Receive Announcement
                                      break;
                                  case 0x08: // Send Announcement
                                      break;
                                  case 0x09: // Wrong password errors
                                      _status = Status.RoomError;
                                      break;
                                  case 0x10: // Send Whisper
                                      break;
                                  case 0x11: // Receive Whisper
                                      break;
                                  case 0x12: // Leave Room
                                      break;
                                  case 0x13: // Disconnect
                                      break;
                              }
                          }
                      }
                  }
              }
          }
      }
  }
  </code></pre>
  
  <p>On another classes I have:</p>
  
  <pre><code>public class SendPackets
  {
      public byte[] Data { get; set; }
      public bool Delay { get; set; }
  }
  
  public enum Status
  {
      Disconnected = 0,
      Connect,
      EnterRequest,
      RoomError,
      Connected
  }
  </code></pre>