【问题标题】:Cancelling a background worker which is continuously reading from a network stream取消不断从网络流中读取的后台工作程序
【发布时间】:2012-02-15 19:28:31
【问题描述】:

我有一个 TCP 服务器正在运行,它定期吐出 2 个字节的消息。

我正在尝试创建一个客户端表单,该表单连接到服务器并不断从流中读取,直到我单击表单上的断开连接按钮。

到目前为止,客户端工作正常,只是我无法断开连接。我将 CancellationPending 设置为 true,但它似乎在 dowork 方法有机会设置 e.Cancel 之前重置为 false。

我也确信必须有一种更可接受的方式来持续读取流并写入表单 - 目前我在 Worker Completed 方法中调用 RunWorkerAsync 来实现循环!

    private void Disconnect()
    {
        commsWorker1.CancelAsync();
    }

    private void ReadFromStream()
    {
        try
        {
            commsWorker1.RunWorkerAsync();
        }
        catch (Exception ex)
        {
            writeToBox("Error: " + ex.Message);
        }
    }

    //background worker dowork method
    private void BackGroundGetServerData(object sender, DoWorkEventArgs e)
    {
        if (true == commsWorker1.CancellationPending)
        {
            e.Cancel = true;
        }
        else
        {
            Byte[] dataArray = new Byte[2];
            try
            {
                _DataStream.Read(dataArray, 0, 2);
                String reply = System.Text.Encoding.ASCII.GetString(dataArray);
                e.Result = reply;
            }
            catch (Exception ex)
            {
            }
        }
    }

    //background worker workercompleted method
    private void BackGroundDisplayMessages(object sender, RunWorkerCompletedEventArgs e)
    {
        if (e.Cancelled)
        {
            //close connection here
        }
        else
        {
            writeToBox((String)e.Result);
            commsWorker1.RunWorkerAsync();
        }

    }
}

}

【问题讨论】:

  • 您是否将 WorkerSupportsCancellation 设置为 true?
  • 抱歉,应该注意了,WorkerSupportsCancellation 和 WorkerSupportsProgress 都是 true。

标签: c# multithreading tcp backgroundworker client-side


【解决方案1】:

你不能在后台工作方法中循环吗?

private void BackGroundGetServerData(object sender, DoWorkEventArgs e)
{
    while(true)
    {
        Byte[] dataArray = new Byte[2];
        try
        {
            _DataStream.Read(dataArray, 0, 2);
            String reply = System.Text.Encoding.ASCII.GetString(dataArray);
            e.Result = reply;
        }
        catch (Exception ex)
        {
            return;
        }
    }
}

然后在断开连接时简单地关闭套接字。这将导致 Exception 被抛出到 while 循环中,您可以通过 catch 块优雅地退出。

Edit:然后您可以在读取每条消息后从循环中更新 GUI。确保您正在更新的控件的句柄可用(假设它名为box):

delegate void updateDelegate(String p);

private void BackGroundGetServerData(object sender, DoWorkEventArgs e)
{
    while(true)
    {
        Byte[] dataArray = new Byte[2];
        try
        {
            _DataStream.Read(dataArray, 0, 2);
            String reply = System.Text.Encoding.ASCII.GetString(dataArray);
            box.BeginInvoke(new updateDelegate(writeToBox), reply);
        }
        catch (Exception ex)
        {
            return;
        }
    }
}

BeginInvoke 在这种情况下是必需的,因为您试图从另一个线程更新 GUI,这是不允许的。此方法将更新转发到 GUI 线程。

【讨论】:

  • 在这种情况下如何调用 BackGroundDisplayMessages?如果我在 DoWork 方法中循环,我想,永远不会调用 WorkerCompleted 方法,所以从流中读取的值永远不会显示?
  • 感谢 Tudor,非常感谢,我采用了您的方法,并且成功了!
【解决方案2】:

您似乎在工作人员完成方法中调用 RunWorkerAsync() 并重置您的 CancellationPending 道具。我认为您可以尝试通过向 Disconnect() 方法添加一些 disconnectFlag = true; 来解决此问题在 WorkerComplete 方法中你应该添加:

if (e.Cancelled || disconnectFlag)
    {
        disconnectFlag = false;
        //close connection here
    } else ...

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多