Как обрабатывать непрерывные получения от клиента TCP в BackgroundWorker? - PullRequest
0 голосов
/ 13 апреля 2019

Я отправляю строковое значение, содержащее некоторые данные, которые мне нужны в моем приложении C #, с помощью соединения TCP-сервер / клиент. Значение строки изменяется 200-300x в секунду.

Теперь то, что я сейчас хочу сделать, это показать значения входящих строк в метке. Я читал об использовании класса BackgroundWorker для этого случая, так как в противном случае пользователь мог бы заморозить интерфейс. Но, к сожалению, это не работает! Сначала я проверил соединение в простом консольном приложении, там оно отлично работало. Вы видите, что я здесь делаю не так?

namespace test
{
    public partial class Form1 : Form
    {

        BackgroundWorker worker;
        IPAddress ip;
        Socket s;
        TcpListener tcp;

        public Form1()
        {
            InitializeComponent();

            ip = IPAddress.Parse("1.2.3.4");
            tcp = new TcpListener(ip, 8001);

            worker = new BackgroundWorker();

            worker.DoWork += new DoWorkEventHandler(TCPServer);
            worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(workerCompleted);

        }

        string data = string.Empty;
        int k = 0;
        byte[] b = new byte[4096];
        private void TCPServer(object sender, DoWorkEventArgs e)
        {
             while (true)
            {
                k = s.Receive(b);
                data = Encoding.ASCII.GetString(b, 0, k);
                e.Result = data.ToString();
            }

        }

        private void workerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            label1.Text = e.Result.ToString();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            tcp.Start();
            s = tcp.AcceptSocket();
            worker.RunWorkerAsync();
        }

    }
}

Ответы [ 2 ]

0 голосов
/ 13 апреля 2019

BackgroundWorker просто запустит вашу задачу в другом потоке, который необходимо периодически вызывать для обновления пользовательского интерфейса

.

Ваш метод workerCompleted используется для обновления label1.Text, но этот метод будет вызываться только после завершения рабочего задания, и похоже, что оно не предназначено для завершения.

Итак, есть пара вещей, которые вы можете сделать:
Вы можете зарегистрировать обработчик событий ProgressChanged для работника и вызвать worker.ReportProgress(progress, data) в обработчике DoWork (ваш метод TCPServer):

// Add to init
worker.WorkerReportsProgress = true;
worker.ProgressChanged = new ProgressChangedEventHandler(WorkerProgressChanged);

private void TCPServer(object sender, DoWorkEventArgs e)
{
  while(true) 
  {
    k = s.Receive(b);
    data = Encoding.ASCII.GetString(b, 0, k);
    int progress = 0; // Or the actual progress if available 
    object param = data.ToString();
    worker.ReportProgress(progress, param);
  }
}

private void workerProgressChanged(object sender, ProgressChangedEventArgs e)
{
  label1.Text = e.Result.ToString();
}

Или вы можете удалить цикл while (true) из метода работы и просто запустить его один раз, а затем в методе workerCompleted снова запустить рабочий:

private void TCPServer(object sender, DoWorkEventArgs e)
{
  k = s.Receive(b);
  data = Encoding.ASCII.GetString(b, 0, k);
  e.Result = data.ToString();
}

private void workerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
  label1.Text = e.Result.ToString();
  worker.RunWorkerAsync();
}

Вы также можете найти вдохновение здесь Как обновить GUI с помощью backgroundworker?

У меня такое чувство, что вам нужно будет перенести следующие вещи в рабочий поток:

TcpListener tcp.Start();
Socket s = tcp.AcceptSocket();

Это похоже на асинхронные действия, которые блокируют поток пользовательского интерфейса


Что бы я на самом деле делал в ваших ботинках:

Поскольку в основном вам нужен сервер, работающий все время, и он уже работает как консольное приложение. Я бы нашел способ запустить приложение, подписаться на его вывод и отобразить информацию в другом приложении, только для пользовательского интерфейса.

Или, по крайней мере, запустить всю серверную часть в отдельном процессе / потоке и отправить обновления в пользовательский интерфейс.

Я думаю, что цель BackgroundWorker состоит в том, чтобы запустить некоторые задачи, которые в противном случае блокировали бы пользовательский интерфейс в другом потоке, но он не должен выполнять бесконечную задачу.

0 голосов
/ 13 апреля 2019

Ваша проблема в том, что метод workerCompleted будет вызываться только после завершения backgroundWorker. Так как ваш TCPServer метод имеет бесконечный цикл, который никогда не произойдет.

Вы можете использовать функциональность ReportProgress вашего backgroundWorker. Но я не думаю, что будет хорошей идеей обновлять ваш лейбл 200-300 раз в секунду.

...