Как сохранить консольное приложение открытым, когда все процессы выполняются в отдельных потоках в c #? - PullRequest
0 голосов
/ 21 ноября 2018

Я пытаюсь создать простое серверное приложение, чтобы изучить основы многопоточного программирования на языке c #.Основная идея проста: клиент подключается к серверу и отправляет: «получить время», чтобы получить текущее время сервера.Все потоки и сокеты tcplistener должны работать на отдельных потоках.Я не уверен, почему, но когда приложение завершает инициализацию всех потоков, консольное приложение закрывается.

Вот код сервера:

class Program
{
    static public int minPort;
    static public int maxPort;
    static int openPort = 0;
    static byte[] sendData = new byte[1024];
    static TcpListener[] listeners;
    static Thread[] connectionThreads;

    static void Main()
    {
        Console.Write("What do you want your minimum port to be? ");
        minPort = Convert.ToInt32(Console.ReadLine());
        Console.Write("What do you want your maximum port to be? ");
        maxPort = Convert.ToInt32(Console.ReadLine());

        //init
        ThreadStart streamThreadStart = new ThreadStart(DataStream);
        openPort = maxPort - minPort;
        listeners = new TcpListener[maxPort - minPort];
        connectionThreads = new Thread[maxPort - minPort];

        for (int i = 0; i == maxPort - minPort; i++)
        {
            listeners[i] = new TcpListener(IPAddress.Any, minPort + i);
            connectionThreads[i] = new Thread(streamThreadStart);
            Thread.Sleep(10);
            openPort = openPort + 1;
        }
    }

    static void DataStream()
    {
        int port = openPort;
        byte[] receiveData = new byte[1024];
        listeners[openPort].Start();
        Socket socket = listeners[port].AcceptSocket();
        NetworkStream stream = new NetworkStream(socket);
        while (true)
        {
            socket.Receive(receiveData);
            Console.WriteLine("Received: " + BitConverter.ToString(receiveData));
            socket.Send(parseCommand(receiveData));
        }

    }
    static byte[] parseCommand(byte[] input)
    {
        string RCommand = BitConverter.ToString(input);
        string SCommand;
        if (RCommand == "get time")
        {
            SCommand = DateTime.Now.ToUniversalTime().ToString();
        }else
        {
            SCommand = "Unknown Command, please try again";
        }
        byte[] output = Encoding.ASCII.GetBytes(SCommand);
        return output;
    }
}

Ответы [ 3 ]

0 голосов
/ 21 ноября 2018

Вам необходимо присоединиться к вашим потокам перед выходом.

static public void Main()
{
    /*
        Existing code goes here
    */

    //Before exiting, make sure all child threads are finished
    foreach (var thread in connectionThreads) thread.Join(); 
}

Когда ваша программа вызывает Thread.Join, она сообщает операционной системе, что ей не нужно планировать основной потокдля любых временных интервалов, пока не закончится дочерний поток.Это делает его более легким, чем другие методы, такие как Ожидание с занятым временем (то есть выполнение цикла while);в то время как основной поток будет по-прежнему удерживать ресурсы, он не будет расходовать процессорное время.

См. также Когда я буду использовать Thread.Join? и c # Ожидание нескольких потоковзакончить

0 голосов
/ 21 ноября 2018

Ваш код не запускает новую тему!Итак, я сделал некоторые изменения в вашем коде:

class Program
    {
        static public int minPort;
        static public int maxPort;
        //static int openPort = 0;
        static byte[] sendData = new byte[1024];
        static TcpListener[] listeners;
        static Thread[] connectionThreads;

        static void Main()
        {
            Console.Write("What do you want your minimum port to be? ");
            minPort = Convert.ToInt32(Console.ReadLine());
            Console.Write("What do you want your maximum port to be? ");
            maxPort = Convert.ToInt32(Console.ReadLine());

            //init
           // ThreadStart streamThreadStart = new ThreadStart(DataStream(0));
            //openPort = minPort;
            listeners = new TcpListener[maxPort - minPort];
            connectionThreads = new Thread[maxPort - minPort];

            //for (int i = 0; i == maxPort - minPort; i++) it can't work
            for (int i = 0; i < maxPort - minPort; i++)
            {
                listeners[i] = new TcpListener(IPAddress.Any, minPort + i);
                connectionThreads[i] = new Thread(new ParameterizedThreadStart(DataStream)); //thread with start parameter
                connectionThreads[i].Start(i); // start thread with index
                Thread.Sleep(10);

            }

        }

        static void DataStream(object o)
        {
            int index = (int)o; //get index
            byte[] receiveData = new byte[1024];
            listeners[index].Start(); // start listener with right index
            Socket socket = listeners[index].AcceptSocket();
            NetworkStream stream = new NetworkStream(socket);
            while (true)
            {
                socket.Receive(receiveData);
                Console.WriteLine("Received: " + BitConverter.ToString(receiveData));
                socket.Send(parseCommand(receiveData));
            }

        }
        static byte[] parseCommand(byte[] input)
        {
            string RCommand = BitConverter.ToString(input);
            string SCommand;
            if (RCommand == "get time")
            {
                SCommand = DateTime.Now.ToUniversalTime().ToString();
            }
            else
            {
                SCommand = "Unknown Command, please try again";
            }
            byte[] output = Encoding.ASCII.GetBytes(SCommand);
            return output;
        }
    }
0 голосов
/ 21 ноября 2018

Как правило, рекомендуется, чтобы консольное приложение предлагало запрос «Введите любой ключ для выхода», когда пользователь хочет остановить приложение.Но вы всегда можете запросить конкретное нажатие клавиши, чтобы выйти, например, 'q'.

Вот код, с которого можно начать:

Console.WriteLine("Press any key to exit..."); Console.ReadKey();

...