如何在BackgroundWorker中处理来自TCP客户端的连续接收?

时间:2019-04-12 22:00:04

标签: c# tcp backgroundworker

我正在通过TCP服务器/客户端连接发送包含我在C#应用程序中所需的一些数据的字符串值。字符串值每秒变化200-300x。

现在,我现在只想在标签中显示传入的字符串值。 我已经读过有关在这种情况下使用BackgroundWorker类的信息,因为否则它将冻结UI。但不幸的是,它不起作用!我首先在一个简单的控制台应用程序中测试了连接,在此应用程序中它运行良好。您可能在这里看到我做错了吗?

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 :(得分:0)

您的问题是,workerCompleted方法只会在backgroundWorker完成时被调用。由于您的TCPServer方法具有无限循环,因此永远不会发生。

您可以使用ReportProgress的{​​{1}}功能。但是我认为根本不每秒200-300次更新标签是个好主意。

答案 1 :(得分:0)

BackgroundWorker只会在需要定期引发事件以更新ui的另一个线程上运行任务

您的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();
}

或者您可以从work方法中删除while(true)周期并仅运行一次,然后在workerCompleted方法中再次启动worker:

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();
}

您也可以在How to update GUI with backgroundworker?

寻求灵感

我感觉到您需要将以下内容移至工作线程:

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

这些看起来像一个异步操作,它将阻止ui线程


我实际上会穿上你的鞋子

由于您基本上需要一台始终运行的服务器,并且已经可以将其用作控制台应用程序。我将找到一种方法来运行该应用程序并订阅其输出,并在另一个仅ui的应用程序中显示信息。

或者至少在单独的进程/线程中运行整个服务器部分,然后将更新发送到ui。

我认为BackgroundWorker的目的是运行一些本来会阻止UI进入另一个线程的任务,但不应运行无尽的任务。