Home Forums Support Problem with single server/multiple clients Reply To: Problem with single server/multiple clients

#2854
Anonymous
Inactive

So the issue turned out to be another instance of bad performance of the .Net ThreadPool. We migrated large parts of our code away from the .Net ThreadPool when moving from version 2.0 to 3.0, in preference of a thread pool we developed ourselves. The one remaining place we were still using the .Net thread pool was in the connection establish code sections. Moving this thread pool to our own version solved the problem.

I have emailed you a link to a hotfix download.

A performance note while debugging this issue, if you would like to establish such a large number of connections simultaneously I recommend you enable synchronous mode on the server object using:

NetworkComms.ConnectionListenModeUseSync = true;

The full example I have used to debug this issue is a slight variation on your own, which I include below for your information.

I apologise a solution to this problem took longer than normal, we have been usually busy with a wide variety of project at the moment.

If you have any further problems please feel free to post back.
Regards,
Marc

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NetworkCommsDotNet;
using System.Threading;
using System.Net;
using NetworkCommsDotNet.DPSBase;
using NetworkCommsDotNet.Tools;
using System.IO;
using InTheHand.Net;
using NetworkCommsDotNet.Connections;
using NetworkCommsDotNet.Connections.Bluetooth;
using NetworkCommsDotNet.Connections.TCP;
using NetworkCommsDotNet.Connections.UDP;
using System.Threading.Tasks;

namespace DebugTests
{
    /*
     * Run multiple clients using a batch script containing the following
     * 
     *  for /l %%i in (1, 1, 100) do (
     *  start "title of the process" "DebugTests.exe" 
     *  )
     */

    /// <summary>
    /// A scrap board class for solving whatever bug is currently causing issues
    /// </summary>
    static class ClientHammer
    {
        public static void RunExample(string[] args)
        {
            if (args.Length == 0 || args[0] == "client")
                RunClient();
            else
                RunServer();
        }

        private static void RunServer()
        {
            //ILogger logger = new LiteLogger(LiteLogger.LogMode.LogFileOnly, "DebugTests_" + NetworkComms.NetworkIdentifier + ".txt");
            //NetworkComms.EnableLogging(logger);

            //Slightly improves performance when we have many simultaneous incoming connections.
            NetworkComms.ConnectionListenModeUseSync = true;

            //Trigger the method PrintIncomingMessage when a packet of type 'Message' is received
            //We expect the incoming object to be a string which we state explicitly by using <string>
            NetworkComms.AppendGlobalIncomingPacketHandler<string>("Message", PrintIncomingMessage);
            NetworkComms.AppendGlobalConnectionEstablishHandler(OnConnectionEstablished);
            NetworkComms.AppendGlobalConnectionCloseHandler(OnConnectionClosed);

            Connection.StartListening(ConnectionType.TCP, new System.Net.IPEndPoint(System.Net.IPAddress.Any, 4000));

            //Print out the IPs and ports we are now listening on
            Console.WriteLine("Server listening for TCP connection on:");
            foreach (System.Net.IPEndPoint localEndPoint in Connection.ExistingLocalListenEndPoints(ConnectionType.TCP))
                Console.WriteLine("{0}:{1}", localEndPoint.Address, localEndPoint.Port);

            //Let the user close the server
            Console.WriteLine("\nPress any key to close server.");
            Console.ReadKey(true);

            //We have used NetworkComms so we should ensure that we correctly call shutdown
            NetworkComms.Shutdown();
        }

        private static void RunClient()
        {
            Console.WriteLine("Client launching ...");

            string Server = "127.0.0.1";
            int Port = 4000;
            string SlaveNameFormat = "Slave {0}";

            var slaveId = System.Diagnostics.Process.GetCurrentProcess().Id;
            var endpoint = new IPEndPoint(IPAddress.Parse(Server), Port);

            var connection = TCPConnection.GetConnection(new ConnectionInfo(endpoint));
            var slaveName = string.Format(SlaveNameFormat, slaveId);

            Console.WriteLine(string.Format("{0} reporting for duty!", slaveName));
            connection.SendObject("Message", string.Format("{0} reporting for duty!", slaveName));
            Thread.Sleep(5000);
            Console.WriteLine(string.Format("{0} unregistering duty!", slaveName));
            connection.SendObject("Message", string.Format("{0} unregistering duty!", slaveName));
            Thread.Sleep(5000);
            Console.WriteLine("Closing");
        }

        private static void OnConnectionClosed(Connection connection)
        {
            Console.WriteLine("Connection closed!");
        }

        private static void OnConnectionEstablished(Connection connection)
        {
            Console.WriteLine("Connection established!");
        }

        private static void PrintIncomingMessage(PacketHeader header, Connection connection, string message)
        {
            Console.WriteLine(message);
        }
    }
}