4
\$\begingroup\$

My server code is currently reading String data over a TCP connection form 2 different client computers. To do this I am duplicating the StreamReader functions for the two separate clients. How can I simplify my code into just one method without having to duplicate for every client? (I want to do 4 clients in the future, duplicating a part of the code 4 times is very tedious and clumsy).

public class AsynchIOServer
{
    static TcpListener tcpListener = new TcpListener(15);
    static TcpListener tcpListener2 = new TcpListener(10);


    static void Listeners()
    {
        using (Socket socketForClient = tcpListener.AcceptSocket())
        {
            if (socketForClient.Connected)
            {
                Console.WriteLine("Client:" + socketForClient.RemoteEndPoint + " now connected to server.");
                using (NetworkStream networkStream = new NetworkStream(socketForClient))
                //using (NetworkStream networkStream2 = new NetworkStream(socketForClient))
                using (System.IO.StreamWriter streamWriter = new System.IO.StreamWriter(networkStream))
                using (System.IO.StreamReader streamReader = new System.IO.StreamReader(networkStream))
                //using (System.IO.StreamReader streamReader2 = new System.IO.StreamReader(networkStream2))
                {
                    try
                    {
                        while (true)
                        {
                            string theString = streamReader.ReadLine();
                            if (string.IsNullOrEmpty(theString) == false)
                            {
                                Console.WriteLine("Kinect1:" + theString);
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine("Error: " + ex.Message);
                    }
                }
            }
        }
        Console.WriteLine("Press any key to exit from server program");
        Console.ReadKey();
    }
//---------------------------------------------------------------------------
    static void Listeners2()
    {
        using (Socket socketForClient2 = tcpListener2.AcceptSocket())
        {
            if (socketForClient2.Connected)
            {
                Console.WriteLine("Client:" + socketForClient2.RemoteEndPoint + " now connected to server.");
                //using (NetworkStream networkStream = new NetworkStream(socketForClient))
                using (NetworkStream networkStream2 = new NetworkStream(socketForClient2))
                using (System.IO.StreamWriter streamWriter = new System.IO.StreamWriter(networkStream2))
                //using (System.IO.StreamReader streamReader = new System.IO.StreamReader(networkStream))
                using (System.IO.StreamReader streamReader2 = new System.IO.StreamReader(networkStream2))
                {
                    try
                    {
                        while (true)
                        {
                            string theString2 = streamReader2.ReadLine();
                            if (string.IsNullOrEmpty(theString2) == false)
                            {
                                Console.WriteLine("Kinect2:" + theString2);
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine("Error: " + ex.Message);
                    }
                }
            }
        }
        Console.WriteLine("Press any key to exit from server program");
        Console.ReadKey();
    }

    public static void Main()
    {
        tcpListener.Start();
        tcpListener2.Start();
        Console.WriteLine("************This is Server program************");
        Console.WriteLine("How many clients are going to connect to this server?:");
        int numberOfClientsYouNeedToConnect =int.Parse( Console.ReadLine());
        for (int i = 0; i < numberOfClientsYouNeedToConnect; i++)
        {
            Thread newThread = new Thread(new ThreadStart(Listeners));
            newThread.Start();
        }

        for (int i = 0; i < numberOfClientsYouNeedToConnect; i++)
        {
            Thread newThread2 = new Thread(new ThreadStart(Listeners2));
            newThread2.Start();
        }
    }
}
\$\endgroup\$
  • 2
    \$\begingroup\$ What happened to the Listeners2? Did you forget to paste it? Please post the complete code, without editing it. Only then we can suggest you how to optimize it. \$\endgroup\$ – t3chb0t Aug 13 '18 at 18:03
  • \$\begingroup\$ @t3chb0t posted the whole code. Didn't post the whole code to make the question shorter. Thanks for your comment and hopefully you can help me optimize it. \$\endgroup\$ – jay.tailor Aug 13 '18 at 18:10
3
\$\begingroup\$

You can use a ParameterizedThreadStart instead of TheadStart and then provide each TcpListener instance as parameter to each new Thread:

  TcpListener[] listeners =
  {
    new TcpListener(15),
    new TcpListener(10)
  };

  foreach (TcpListener listener in listeners)
  {
    listener.Start();
    for (int i = 0; i < numberOfClientsYouNeedToConnect; i++)
    {
      Thread newThread = new Thread(new ParameterizedThreadStart(Listeners));
      newThread.Start(listener);
    }
  }

You'll then have to change the signature of the Listeners-function:

static void Listeners(object state)
{
  TcpListener listener = state as TcpListener;
  using (Socket socketForClient = listener.AcceptSocket())
  {
     ...

EDIT:

If you want to provide more information to the thread function, you can create a class, that holds any information beside the TcpListener object:

  public class ListenerInfo
  {
    public ListenerInfo(TcpListener listener, string name, int index)
    {
      Listener = listener;
      Name = name;
      Index = index;
    }

    public TcpListener Listener { get; }
    public string Name { get; }
    public int Index { get; }
  }

You can then create the threads like this:

  var infos = new []
  {
    new { Listener = new TcpListener(15), Name = "Listener 15" },
    new { Listener = new TcpListener(10), Name = "Listener 10" }
  };

  foreach (var info in infos)
  {
    for (int i = 0; i < numberOfClientsYouNeedToConnect; i++)
    {
      Thread newThread = new Thread(new ParameterizedThreadStart(AsynchIOServer.Listeners));
      newThread.Start(new ListenerInfo(info.Listener, info.Name, i));
    }
  }

And modify the thread-function to handle the new object:

public static void Listeners(object state)
{
  ListenerInfo listenerInfo = state as ListenerInfo;
  using (Socket socketForClient = listenerInfo.Listener.AcceptSocket())
  {
    if (socketForClient.Connected)
    {
      Console.WriteLine("Client:" + socketForClient.RemoteEndPoint + " now connected to server.");
      using (NetworkStream networkStream = new NetworkStream(socketForClient))
      //using (NetworkStream networkStream2 = new NetworkStream(socketForClient))
      using (System.IO.StreamWriter streamWriter = new System.IO.StreamWriter(networkStream))
      using (System.IO.StreamReader streamReader = new System.IO.StreamReader(networkStream))
      //using (System.IO.StreamReader streamReader2 = new System.IO.StreamReader(networkStream2))
      {
        try
        {
          while (true)
          {
            string theString = streamReader.ReadLine();
            if (string.IsNullOrEmpty(theString) == false)
            {
              Console.WriteLine($"Connection {listenerInfo.Name} {listenerInfo.Index}: {theString}");
            }
          }
        }
        catch (Exception ex)
        {
          Console.WriteLine("Error: " + ex.Message);
        }
      }
    }
  }
  Console.WriteLine("Press any key to exit from server program");
  Console.ReadKey();
}

What is your break/stop-condition for the while (true)-loop in the Listener()-method?

\$\endgroup\$
  • 1
    \$\begingroup\$ The break for the while loop is when there is no stream being sent from the client computer. in other words, when the TCP connection breaks. \$\endgroup\$ – jay.tailor Aug 14 '18 at 14:50
  • \$\begingroup\$ When we run the program, the server computer is only displaying the stream from one client, even though both clients are connected. If you look at the while loop, there is only one string variable "theString". (Now that we have taken out Listeners2). Do we need to create a another variable and another console.writeline so the server computer can output both client streams? \$\endgroup\$ – jay.tailor Aug 14 '18 at 15:03
  • \$\begingroup\$ @jay.tailor: I'm sure if I understand you the right way, but no, the variable theString is a local variable which is not shared between different calls to Listener(object state) { ... }. \$\endgroup\$ – Henrik Hansen Aug 14 '18 at 15:30
  • \$\begingroup\$ I mean to say that the stream worked from 2 clients when i duplicated the Listeners functions, and created a new one named it Listeners2. Then i duplicated every variable. Is this the only way to have multiple client strings read by the server? Do I need N number of string variables on the server side for the N number of clients I have? \$\endgroup\$ – jay.tailor Aug 14 '18 at 15:35
  • \$\begingroup\$ @jay.tailor: I still don't quite understand what you mean, but see my Edit, maybe you can use that. \$\endgroup\$ – Henrik Hansen Aug 15 '18 at 7:36

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.