Приложение не отвечает после acceptcpclient()

#c# #wpf #tcpclient #tcplistener

Вопрос:

Когда я запускаю два экземпляра своего приложения, они должны подключиться и иметь возможность отправлять приветственное сообщение другому приложению. Я знаю, что они подключаются, потому что клиентская сторона покажет, что сообщение отправлено и даже получено с сервера. Однако видна только сторона клиента. Сервер «замораживается», как только я нажимаю «Пуск». Я что-то не так использую? Изображение замороженного и видимого приложения

 private void Startbutton_Click(object sender, RoutedEventArgs e)
    {
        try
        {

            listener = new TcpListener(localAddr, port);
            ChatScreentextBox.AppendText("waiting for connection..."   "n");
            listener.Start();

            // Buffer for reading data
            Byte[] bytes = new Byte[256];
            String data = null;

            while (true)
            {
                TcpClient client = listener.AcceptTcpClient();
                

                data = null;

                // Get a stream object for reading and writing
                NetworkStream stream = client.GetStream();

                int i;

                // Loop to receive all the data sent by the client.
                while ((i = stream.Read(bytes, 0, bytes.Length)) != 0)
                {
                    // Translate data bytes to a ASCII string.
                    data = System.Text.Encoding.ASCII.GetString(bytes, 0, i);
                    ChatScreentextBox.AppendText(data);

                    // Process the data sent by the client.
                    data = data.ToUpper();

                    byte[] msg = System.Text.Encoding.ASCII.GetBytes(data);

                    // Send back a response.
                    stream.Write(msg, 0, msg.Length);
                    ChatScreentextBox.AppendText(data   "connection");
                }

                // Shutdown and end connection
                client.Close();
            }                
        }
        catch (SocketException ex)
        {
            MessageBox.Show(ex.Message.ToString());
        }
        finally
        {
            // Stop listening for new clients.
            listener.Stop();
        }

    }

private void Connectbutton_Click(object sender, RoutedEventArgs e)
    {
        try
        {
            // Create a TcpClient.
            // Note, for this client to work you need to have a TcpServer
            // connected to the same address as specified by the server, port
            // combination.
            Int32 port = 88;
            TcpClient client = new TcpClient("127.0.0.1", port);

            // Translate the passed message into ASCII and store it as a Byte array.
            Byte[] data = System.Text.Encoding.ASCII.GetBytes("hello");

            // Get a client stream for reading and writing.
            //  Stream stream = client.GetStream();

            NetworkStream stream = client.GetStream();

            // Send the message to the connected TcpServer.
            stream.Write(data, 0, data.Length);

            //Console.WriteLine("Sent: {0}", message);
            ChatScreentextBox.AppendText(data   "n");


            // Receive the TcpServer.response.

            // Buffer to store the response bytes.
            data = new Byte[256];

            // String to store the response ASCII representation.
            String responseData = String.Empty;

            // Read the first batch of the TcpServer response bytes.
            Int32 bytes = stream.Read(data, 0, data.Length);
            responseData = System.Text.Encoding.ASCII.GetString(data, 0, bytes);
            ChatScreentextBox.AppendText("you:"   responseData   "thisn");

            // Close everything.
            stream.Close();
            client.Close();
        }
        catch (ArgumentNullException ex)
        {
            MessageBox.Show(ex.Message.ToString());
        }
        catch (SocketException ex)
        {
            MessageBox.Show(ex.Message.ToString());
        }
        
    }
 

Ответ №1:

Вы принимаете TCPClient событие щелчка по кнопке в бесконечном while цикле. Это является причиной того, что приложение перестает отвечать на запросы.

Что вам нужно сделать, так это запустить это в отдельном потоке. BackgroundWorker это мой предпочтительный способ сделать это. Task является также относительно новым и популярным.

Существует множество примеров того, как использовать и то, и другое. В двух словах, если вы идете с BackgroundWorker , вам нужно создать поле типа BackgroundWorker , у вас есть все ваши «мозги» в DoWork событии, затем с помощью кнопки Нажмите событие, просто вызовите .RunWorkerAsync() метод.

Если это неясно и вам нужна дополнительная помощь, просто прокомментируйте здесь.

Комментарии:

1. Огромное спасибо. Я не совсем понимаю, что такое «ум», я довольно новичок в программировании. Я предполагаю, что это означает поместить весь TcpListener, AcceptTcpClient в событие DoWork?

2. Да, точно, все содержимое вашего Click события должно быть в DoWork случае BackgroundWorker экземпляра.

3. Большое вам спасибо, это решило мою проблему!

4. Мы вам очень рады. Я создал для вас полный пример (хотя и в качестве приложения WinForms), есть еще несколько вещей, которые нужно изменить. А именно: while(true) больше не годится, и прямой доступ из потока BackgroundWorker очень нахмурен. Лучший способ сделать это-включить отчеты о ходе выполнения и сообщить некоторое число (для этой цели я использую отрицательные числа) со строкой, чтобы ProgressChanged событие могло получить доступ к элементам управления и обновить текст. Если вы хотите, скачайте и посмотрите на источник: drive.google.com/file/d/1TWodTJ35KRtY3rRLNv6NDw1PetrD-SRO/…

Ответ №2:

Когда вы принимаете соединение и запускаете (цикл while) для чтения данных из соединения, оно блокирует действие, и вы выполняете это действие в основном потоке (в котором выполняется процедура обновления пользовательского интерфейса). Когда вы принимаете соединение, вы считываете данные, но пользовательский интерфейс никогда не обновляется, потому что поток все еще читает/ожидает данные.

Чтобы исправить это, вам нужно запустить это действие чтения в отдельном потоке для обработки чтения и обработки. Вы можете увидеть пример здесь.

Чтобы узнать больше о потоковой передаче в C#, см. Пример здесь или прочитайте документы Microsoft.