Проблемы с потоками при использовании Ping для сопоставления активных IP-адресов - C # - PullRequest
1 голос
/ 21 января 2010

Я пытаюсь создать простой сетевой инструмент для проверки всех возможных IP-адресов в локальной подсети и предоставления списка таких IP-адресов в DataGridView. Я новичок в том, что нужно рассмотреть многопоточность, и это хорошая вещь, которую можно встретить как начинающего программиста. Извините, но вам, вероятно, придется кое-что объяснить мне, но, на мой взгляд, это должно сработать. Прежде чем я попытался поместить его в поток фонового работника, приложение просто зависало и давало мне сообщение «Не отвечает».

спасибо заранее.

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

            }


    }

Ответы [ 3 ]

2 голосов
/ 21 января 2010

Вы не можете получить прямой доступ к progressBar1 (или любому другому элементу пользовательского интерфейса) из события «DoWork» backgroundWorker1, вы должны использовать метод 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;
}
1 голос
/ 21 января 2010

Часть проблемы заключается в том, что вы напрямую обращаетесь к элементу пользовательского интерфейса из фонового потока. Поле progressBar предположительно является элементом управления индикатором пользовательского интерфейса и может быть безопасно доступно только из потока пользовательского интерфейса. Вы должны использовать вызов .Invoke, чтобы установить это значение из потока пользовательского интерфейса.

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

private void UpdateProgressBarByOne() {
  progressBar.Value += 1;  
}
0 голосов
/ 21 января 2010

Ах, я люблю нить. Это делает программы намного интереснее ...

Итак, когда я начал изучать, как создавать адаптивные приложения, я наткнулся на функцию: Application.DoEvents ()

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

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

т.е. в обработчике события при нажатии

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

Теперь это было в дни, предшествующие точечным сетям, и оно сохранилось до сих пор, однако, это не то, что вы должны воспринимать легкомысленно. Если вы нажмете другую кнопку в форме, она запустит другой поток, который попытается выполнить, и если вы не будете осторожны, вызовите исключения потока в вашей форме. Некоторые разработчики скажут, что вы этим не пользуетесь, но с момента вашего старта я бы сказал, попробуйте:)

Я не могу использовать этот метод в зависимости от приложения. Вместо этого я бы на самом деле создал несколько «обработок» обработки; по одному на каждое ядро ​​процессора, которое было в системе. Я бы добавил 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) в моей форме, я бы соответственно обновил информацию об интерфейсе пользователя.

Многопоточность - это весело, чувак :) Со временем вы можете обнаружить, что вы можете использовать MSMQ для создания системы, которая использует многоядерные системы других компьютеров для выполнения таких задач, как обработка изображений (или что-то с помощью .......; ) * * тысяча двадцать-один

...