2012-01-25 2 views
-1

Я создал 2 программы. Оба используют таймеры с интервалом в 250 миллисекунд.Моя программа блокировки, когда я запускаю таймер, и я не уверен, почему

Проблема в том, что моя первая программа не блокируется, я запускаю ее, а второй блокирует, давая мне возможность нажать кнопку остановки. Говоря о блокировках, я имею в виду, что программа работает, пока она не остановит ее от VS.

Я не понимаю, почему я не могу остановить свою первую программу, в то время как основной способ работы для другой программы. Есть идеи?

Программа, которая блокирует:

private void btnScan_Click(object sender, EventArgs e) 
    { 
     tmrInterval.Interval = (int)nudInterval.Value; 
     tmrInterval.Start(); 
    } 

    private void ScanPort(IPAddress address, int port) 
    { 
     using (TcpClient client = new TcpClient()) 
     { 
      IAsyncResult result = client.BeginConnect(address, port, null, null); 

      if (result.AsyncWaitHandle.WaitOne((int)nudTimeout.Value, false)) txtDisplay.AppendText("Port: " + port + " is open." + Environment.NewLine); 
      else txtDisplay.AppendText("Port: " + port + " is closed." + Environment.NewLine); 
     } 
    } 

    private void btnStop_Click(object sender, EventArgs e) 
    { 
     tmrInterval.Stop(); 
    } 

    private void tmrInterval_Tick(object sender, EventArgs e) 
    { 
     ScanPort(IPAddress.Parse(txtIP.Text), currentPort); 
     currentPort++; 
     if (currentPort == nudTo.Value) tmrInterval.Stop(); 
    } 

Программа, которая не блокирует:

void tmrPingInterval_Tick(object sender, EventArgs e) 
    { 
     if (txtTo.Text == string.Empty) Ping(IPAddress.Parse(ip2str(startIP))); 
     else 
     { 
      if (currentIP >= endIP) tmrPingInterval.Stop(); 
      Ping(IPAddress.Parse(ip2str(currentIP))); 
      currentIP++; 
     } 
    } 

    private void btnPing_Click(object sender, EventArgs e) 
    { 
     if (txtFrom.Text != string.Empty) 
     { 
      txtFrom.Enabled = false; 
      txtTo.Enabled = false; 
      txtDisplay.Text = string.Empty; 
      tsslPingCount.Text = string.Empty; 
      count = 0; 
      open = 0; 
      closed = 0; 
      tmrPingInterval.Interval = int.Parse(nudInterval.Value.ToString()); 

      try 
      { 
       startIP = str2ip(txtFrom.Text); 
       if (txtTo.Text != string.Empty) endIP = str2ip(txtTo.Text); 
       currentIP = startIP; 
       tmrPingInterval.Start(); 
      } 
      catch 
      { 
       MessageBox.Show("Input must be in IP format: 100.100.100.100", "Information", MessageBoxButtons.OK, MessageBoxIcon.Information); 
       txtFrom.Enabled = true; 
       txtTo.Enabled = true; 
      } 
     } 
     else MessageBox.Show("IP field cannot be empty!", "Information", MessageBoxButtons.OK, MessageBoxIcon.Information); 
    } 

    private void btnStop_Click(object sender, EventArgs e) 
    { 
     txtFrom.Enabled = true; 
     txtTo.Enabled = true; 
     tmrPingInterval.Stop(); 
    } 

    private void Ping(IPAddress address) 
    { 
     Ping pingSender = new Ping(); 
     PingOptions options = new PingOptions(); 
     if (cbDontFragment.Checked) options.DontFragment = true; 
     else options.DontFragment = false; 
     string data = string.Empty; 
     int dataCounter = 0; 
     options.Ttl = (int)nudTTL.Value; 

     for (int i = 0; i < nudData.Value; i++) 
     { 
      dataCounter++; 
      if (dataCounter == 10) dataCounter = 0; 
      data += dataCounter.ToString(); 
     } 

     byte[] buffer = Encoding.ASCII.GetBytes(data); 
     int timeout = 120; 
     try 
     { 
      PingReply reply = pingSender.Send(address, timeout, buffer, options); 

      if (reply.Status == IPStatus.Success) 
      { 
      } 
      else 
      { 
      } 
     } 
     catch (Exception ex) 
     { 
      txtDisplay.SelectedText += Environment.NewLine + ex.Message; 
     } 
    } 
+0

Возможно, это связано с тем, что tmrPingInterval имеет резьбу. – Nix

+0

@Nix, я не использовал нити в обоих этих примерах. – HelpNeeder

+0

tmrPingInterval - это таймер? и что вызывает .Ping (.Пожалуйста, напишите больше своего кода. – Nix

ответ

1

Я собираюсь сделать это, потому что у нас недостаточно информации. Я предполагаю, что tmrInterval в System.Windows.Forms.Timer. Если это так, то происходит то, что когда таймер тикает, он передается как сообщение Windows (так же, как обрабатываются щелчки мыши, нажатия клавиш и все остальное, что делает ваше приложение «незамороженным»).

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

Во втором приложении вы делаете что-то относительно быстро, просто отправляя пинг где-то. то, что вы, вероятно, увидите во втором приложении, заключается в том, что ваше приложение будет «заикаться» - перестанет отвечать на секунду или меньше, пока оно запишет любую другую машину, на которую вы указали ее. Он не зависает, потому что поток пользовательского интерфейса не получает столько работы.

Чтобы исправить это, вы должны изучить реализацию BackgroundWorker. Таймеры (любого типа) обычно не считаются хорошим способом создания фоновых задач в .NET.

+0

Похоже, что это объяснение имеет смысл. – HelpNeeder

+0

Я еще не использовал фона рабочего в какой-либо из моих программ. Как мне реализовать свою программу для использования рабочего? Я инициализирую таймер внутри фонового работника? – HelpNeeder

+0

Есть много практических статей об использовании фонового работника.Например: http://www.dotnetperls.com/backgroundworker. Вам не нужен таймер, просто используйте цикл. Все, что вы используете для этого таймера, - это увеличить номер порта, который вы используете. –

1

О первом образце:

Я думаю, из контекста, что таймер является Windows. Forms.Timer. В прошедшем событии вы выполняете WaitOne() и эффективно блокируете Messagepump.

В качестве возможного решения замените таймер на Threading.Timer, чтобы отделить ввод-вывод от основной нити.

+0

Он взаимодействует с пользовательским интерфейсом в событии галочки ... –

+0

Да, я знаю. Эта часть должна быть перемещена или синхронизирована. –

+0

Я знаю это, но я предполагаю, что OP не делает. Просто вы можете рассказать о том, как это сделать, чтобы предотвратить неизбежный «Доступ к контролю» из потока, отличного от вопроса о пользовательском интерфейсе. –

Смежные вопросы