简体   繁体   English

使用Ping映射活动IP的线程问题-C#

[英]Threading issues using Ping to map active IPs - C#

I am trying to create a simple Network Tool to ping all possible IPs on your local subnet and provide a list of such IPs in a DataGridView. 我正在尝试创建一个简单的网络工具来ping您本地子网上的所有可能的IP,并在DataGridView中提供此类IP的列表。 I am new to having to consider threading which is a good thing to come across as a budding programmer. 我是新来的必须考虑线程处理的人,这是一个崭露头角的程序员的好东西。 Sorry, but you are probably going to have to do some explaining to me, but in my mind this should work. 抱歉,您可能需要向我做一些解释,但是在我看来,这应该可以工作。 Before I tried putting it in a backgroundworker thread, the application would just hang and give me a "Not Responding". 在尝试将其放入backgroundworker线程之前,该应用程序将挂起并给我“无响应”。

thanks ahead of time. 提前谢谢。

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

            }


    }

You cannot access directly the progressBar1 (or any other UI element) from the backgroundWorker1 "DoWork" event, you have to use the backgroundWorker1.ProgressChanged method and handle ProgressChanged event: 您无法从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 should be assigned to true and the event of ProgressChanged to the following method 应该将WorkerReportsProgress分配为true,并将ProgressChanged事件更改为以下方法

private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
    // assuming the Minimum = 0 and Maximum = 100 on progressBar
    progressBar.Value = e.ProgressPercentage;
}

Part of the problem is that you are directly accessing a UI element from your background thread. 问题的一部分是您直接从后台线程访问UI元素。 The field progressBar is presumably a UI progress bar control and can only be safely accessed from the UI thread. 字段progressBar大概是UI进度条控件,只能从UI线程安全地访问。 You must use a call to .Invoke to set this value from the UI thread. 您必须使用对.Invoke的调用才能从UI线程设置此值。

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

private void UpdateProgressBarByOne() {
  progressBar.Value += 1;  
}

Ah I love threading. 啊,我喜欢穿线。 It makes programs so much more interesting... 它使程序变得更加有趣...

So as I started off learning about how to make responsive applications I came across the function: Application.DoEvents() 因此,当我开始学习如何制作响应式应用程序时,我遇到了以下函数:Application.DoEvents()

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

What this does is causes your form to process some of the window events it's receiving. 这样做是使您的表单处理正在接收的某些窗口事件。 I think that your code could change to include a call after each ping request... 我认为您的代码可能会更改为在每个ping请求之后都包含一个调用...

ie within the on click event handler 即在点击事件处理程序中

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.
            }

Now this was back in the pre dot net days and it's survived till now however, it's not something that you should take lightly. 现在,这已回到点网时代之前,并且一直存在到现在,但是,这不是您应该掉以轻心的事情。 If you click another button on the form it will start off another thread that will attempt to execute and if you're not careful cause thread exceptions on your form. 如果单击表单上的另一个按钮,它将启动另一个线程,该线程将尝试执行,并且如果您不小心会导致表单上的线程异常。 Some developers will tell you don't use this but since your starting off I'd say give it a shot :) 一些开发人员会告诉您不要使用此功能,但自您开始以来,我想尝试一下:)

I might not use this method depending on the application. 根据应用程序的不同,我可能不会使用此方法。 Instead what I would do it actually do is to create several processing "trains"; 相反,我实际要做的是创建多个处理“火车”。 one for each cpu core that the system had. 系统拥有的每个cpu核心一个。 I'd add the ips to be scanned to a queue object and then I would start up 2 to 4 instances of threads ( http://msdn.microsoft.com/en-us/library/system.threading.thread.aspx ) each of which taking an item off the queue in turn, process the information (ie do the ping logic) and put the result on another queue; 我将要扫描的ips添加到队列对象中,然后启动2到4个线程实例( http://msdn.microsoft.com/zh-cn/library/system.threading.thread.aspx )每一个依次将一个项目从队列中取出,处理信息(即执行ping逻辑)并将结果放在另一个队列中; and output queue. 和输出队列。 Every time a train would finish an item for work it would raise an event at the other end of which there would be a handler in the form. 每次火车要完成一项工作时,都会在另一端引发一个事件,该事件的形式是处理程序。 Using the Invoke to make thread safe calls ( http://msdn.microsoft.com/en-us/library/ms171728.aspx ) on my form I would update the UI's information accordingly. 使用窗体上的Invoke进行线程安全调用( http://msdn.microsoft.com/zh-cn/library/ms171728.aspx ),我将相应地更新UI信息。

Threading is fun dude :) over time you can find that you can use MSMQ to make a system that uses the multicores of other computers to do jobs such as image processing (or something with pa....... ;) 线程很有趣:)随着时间的流逝,您会发现可以使用MSMQ来创建一个使用其他计算机的多核来完成诸如图像处理(或带有pa .......;之类的工作)的系统。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM