2011-12-23 151 views
0

我有一個端口掃描工具,我遇到的問題是,當端點無法訪問時,GUI會凍結,直到出現某種錯誤。我已經嘗試創建一個線程,但我不太熟悉如何去做。有人能告訴我如何?線程在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()。但這不是真正的問題,因爲您已經在使用新的線程。

第二個問題是,您不能從主線程以外的其他線程更新GUI。

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

如果你不喜歡的東西Invoke,您可以使用BackgroundWorker及其ReportProgress方法+ ProgressChanged事件。

@Hmm是正確的,因爲您不使用新的Thread對象,所以在GUI線程上調用該方法。但是,如上所述,您需要更新Invoke

EDIT

順便說一句,在乾淨的解決方案將是,以履行seperation of concerns使用AOP(OnGuiThreadAttribute)。

+0

良好的資源可用在代碼項目上:http://www.codeproject.com/KB/threads/CSharpAsynchronousHelper2.aspx – Hmm 2011-12-23 01:36:40

+1

我認爲最好的方法是使用[PostSharp](http://www.sharpcrafters.com/ )。看看[OnGuiThreadAttribute](http://www.sharpcrafters.com/solutions/multithreading)! – Matthias 2011-12-23 01:39:37

+0

謝謝,一定會有閱讀,看起來很有趣。 – Hmm 2011-12-23 01:45:06

1

如果您正在構建需要在單獨線程上執行任務的Windows Forms應用程序,那麼我建議您使用BackgroundWorker組件。有關如何在http://www.dotnetperls.com/backgroundworker上使用此組件的絕佳教程。