1

我正在尝试创建一个简单的网络工具来 ping 本地子网上所有可能的 IP,并在 DataGridView 中提供此类 IP 的列表。我是新手,不得不考虑线程,这对于一个初出茅庐的程序员来说是一件好事。抱歉,您可能需要向我解释一下,但在我看来,这应该可行。在我尝试将其放入后台工作线程之前,该应用程序只会挂起并给我一个“无响应”。

提前谢谢。

        private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
    {
        count = 0;
        for (int j = 1; j < 255; j++)
            for (int i = 1; i < 255; i++)
            {
                Ping ping = new Ping();
                PingReply pingreply = ping.Send(IPAddress.Parse(locip[0] + "." + locip[1] + "." + j + "." + i));

                if (pingreply.Status == IPStatus.Success)
                {
                    status = "o";
                    repAddress = pingreply.Address.ToString(); ;
                    repRoundtrip = pingreply.RoundtripTime.ToString();
                    repTTL = pingreply.Options.Ttl.ToString();
                    repBuffer = pingreply.Buffer.Length.ToString();

                    string[] lineBuffer = { status, repAddress, repRoundtrip, repTTL, repBuffer };
                    ipList.Rows.Add(lineBuffer);
                    count += 1;
                    progressBar.Value += 1;
                }

            }


    }
4

3 回答 3

2

您不能从 backgroundWorker1“DoWork”事件直接访问 progressBar1(或任何其他 UI 元素),您必须使用 backgroundWorker1.ProgressChanged 方法并处理 ProgressChanged 事件:

// instead of progressBar.Value += 1
// use the following

const int total = 254 * 254;
backgroundWorker1.ReportProgress(count / total);

WorkerReportsProgress 应该被赋值为 true 并且 ProgressChanged 的​​事件被赋值给下面的方法

private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
    // assuming the Minimum = 0 and Maximum = 100 on progressBar
    progressBar.Value = e.ProgressPercentage;
}
于 2010-01-20T23:58:23.243 回答
1

部分问题是您正在从后台线程直接访问 UI 元素。该字段progressBar可能是一个 UI 进度条控件,只能从 UI 线程安全访问。您必须调用 .Invoke 从 UI 线程设置此值。

progressBar.Invoke(new MethodInvoker(UpdateProgressBarbyOne));
...

private void UpdateProgressBarByOne() {
  progressBar.Value += 1;  
}
于 2010-01-20T23:35:55.103 回答
0

啊,我喜欢穿线。它使程序变得更加有趣......

所以当我开始学习如何制作响应式应用程序时,我遇到了这个函数:Application.DoEvents()

(http://msdn.microsoft.com/en-us/library/system.windows.forms.application.doevents.aspx)

这样做会导致您的表单处理它接收到的一些窗口事件。我认为您的代码可能会更改为在每个 ping 请求后包含一个调用...

即在点击事件处理程序中

count = 0;
        for (int j = 1; j < 255; j++)
            for (int i = 1; i < 255; i++)
            {
                Ping ping = new Ping();
                PingReply pingreply = ping.Send(IPAddress.Parse(locip[0] + "." + locip[1] + "." + j + "." + i));

                if (pingreply.Status == IPStatus.Success)
                {
                    status = "o";
                    repAddress = pingreply.Address.ToString(); ;
                    repRoundtrip = pingreply.RoundtripTime.ToString();
                    repTTL = pingreply.Options.Ttl.ToString();
                    repBuffer = pingreply.Buffer.Length.ToString();

                    string[] lineBuffer = { status, repAddress, repRoundtrip, repTTL, repBuffer };
                    ipList.Rows.Add(lineBuffer);
                    count += 1;
                    progressBar.Value += 1;
                }
                Application.DoEvents(); //but not too often.
            }

现在这又回到了 dot net 之前的时代,并且一直存在到现在,但是,这不是您应该掉以轻心的事情。如果您单击表单上的另一个按钮,它将启动另一个尝试执行的线程,如果您不小心会导致表单上的线程异常。一些开发人员会告诉你不要使用它,但自从你开始我会说试一试:)

根据应用程序,我可能不会使用此方法。相反,我实际上会做的是创建几个处理“火车”;系统拥有的每个 cpu 核心一个。我会将要扫描的 ips 添加到队列对象中,然后启动 2 到 4 个线程实例(http://msdn.microsoft.com/en-us/library/system.threading.thread.aspx)每个队列依次从队列中取出一个项目,处理信息(即执行 ping 逻辑)并将结果放入另一个队列;和输出队列。每次火车完成一项工作时,它都会引发一个事件,在该事件的另一端会有一个处理程序。使用 Invoke 进行线程安全调用 ( http://msdn.microsoft.com/en-us/library/ms171728.aspx) 在我的表单上,我会相应地更新 UI 的信息。

线程很有趣,伙计:)随着时间的推移,您会发​​现您可以使用 MSMQ 制作一个系统,该系统使用其他计算机的多核来执行诸如图像处理之类的工作(或与 pa....... ;)

于 2010-01-21T00:34:55.340 回答