2011-12-23 2 views
0

У меня есть инструмент, который выполняет сканирование портов, проблема, с которой я сталкиваюсь, заключается в том, что когда конечная точка недоступна, графический интерфейс зависает, пока не получится какая-то ошибка. Я попытался создать поток, но я не слишком хорошо разбираюсь в том, как это сделать. Может ли кто-нибудь показать мне, как?Threading in GUI

using System; 
using System.Collections.Generic; 
using System.ComponentModel; 
using System.Data; 
using System.Drawing; 
using System.Linq; 
using System.Text; 
using System.Windows.Forms; 
using System.Net; 
using System.Net.Sockets; 
using System.Threading; 

namespace PortScan 
{ 
    public partial class Form1 : Form 
    { 


     public Form1() 
     { 
      InitializeComponent(); 
      timeTextBox.Text = "2000"; 
     } 

     private void button1_Click(object sender, EventArgs e) 
     { 
      ThreadStart threadStart = GetPortStatus; 
      threadStart.BeginInvoke(null, null); 
      GetPortStatus(); 
     } 

     private void GetPortStatus() 
     { 
      button1.Enabled = false; 
      var currentIP = ipaddressTextBox.Text; 
      int anInteger; 
      anInteger = Convert.ToInt32(portTextBox.Text); 
      anInteger = int.Parse(portTextBox.Text); 

      IPAddress IP = IPAddress.Parse(currentIP); 
      IPEndPoint EndPoint = new IPEndPoint(IP, anInteger); 

      Socket query = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); 

      //Console.WriteLine("Blocking: {0}", query.Blocking); 

      //resultsTextBox.Text = currentIP + ":" + anInteger + " is blocked: " + query.Blocking; 
      //resultsTextBox.Text += Environment.NewLine + currentIP + ":" + anInteger + " is blocked: " + query.Blocking; 
      try 
      { 
       query.Connect(EndPoint); 
       resultsTextBox.Text += "Connected to " + EndPoint + Environment.NewLine; 
      } 
      catch (SocketException i) 
      { 
       //Console.WriteLine("Problem connecting to host"); 
       //Console.WriteLine(e.ToString()); 
       resultsTextBox.Text += "Cannot connect to " + EndPoint + ", port maybe blocked" + Environment.NewLine; 
       query.Close(); 
       button1.Enabled = true; 
       return; 
      } 
      //if (InvokeRequired) 
      //{ 
      // Invoke(new MethodInvoker(Close)); 
      //} 
      //else 
      //{ 
      // Close(); 
      //} 

      query.Close(); 
      button1.Enabled = true; 
     } 
     private void timer1_Tick(object sender, EventArgs e) 
     { 
      if (autoCheckBox.Checked == true) 
      { 
       button1_Click(sender, e); 
      } 
      else 
      { 
      } 
     } 

     private void Form1_Load(object sender, EventArgs e) 
     { 

     } 
    } 
} 

ответ

1
private void button1_Click(object sender, EventArgs e) 
    { 
     ThreadStart threadStart = GetPortStatus; 
     threadStart.BeginInvoke(null, null); 
     GetPortStatus(); 
    } 

Должно быть:

private void button1_Click(object sender, EventArgs e) 
    { 
     ThreadStart threadStart = new ThreadStart(GetPortStatus); 
     Thread name = new Thread(threadStart); 
     name.Start(); 
    } 

Вы передать делегат функции, которую Вы хотите вызвать в конструкторе ThreadStart. Threadstart представляет собой метод, который выполняется в потоке.

1

Первой проблемой является то, что Socket.Connect() является блокирующим методом. Он не будет возвращаться до тех пор, пока соединение не будет выполнено/отказано. Вместо асинхронных методов вы можете использовать BeginConnect() и EndConnect(). Но это не настоящая проблема, потому что вы уже используете новый поток.

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

 Invoke(new MethodInvoker(() => 
     { 
       ... // GUI updates (like your resultsTextBox) 
     })); 

Если вы не любите Invoke вещи, вы можете использовать BackgroundWorker и его метод ReportProgress + ProgressChanged событие.

И @Hmm правы, так как вы не используете новый объект Thread, метод вызывается в потоке графического интерфейса. Но вам нужно обновить Invoke, как я описал выше.

EDIT

Btw, чистейшее решение было бы использовать АОП (OnGuiThreadAttribute) для выполнения seperation of concerns.

+0

Хороший доступный ресурс по проекту кода: http://www.codeproject.com/KB/threads/CSharpAsynchronousHelper2.aspx – Hmm

+1

Я думаю, что лучший способ - использовать [PostSharp] (http://www.sharpcrafters.com/)). Взгляните на [OnGuiThreadAttribute] (http://www.sharpcrafters.com/solutions/multithreading)! – Matthias

+0

Спасибо, обязательно прочитайте, выглядит интересно. – Hmm

1

Если вы создаете приложение Windows Forms, которое должно выполнять задачи в отдельном потоке, я бы рекомендовал вам использовать компонент BackgroundWorker. Существует отличный учебник по использованию этого компонента по адресу http://www.dotnetperls.com/backgroundworker.