2012-06-24 134 views
0

我做在C#端口掃描器,但我似乎不能讓它走得更快:端口掃描器慢

private void Scan() 
{ 
    int startPort = Convert.ToInt32(txtFrom.Text); 
    int endPoint = Convert.ToInt32(txtTo.Text); 

    progressBar1.Value = 0; 
    progressBar1.Maximum = endPoint - startPort + 1; 

    for (int currPort = startPort; currPort <= endPoint; currPort++) 
    { 
     TcpClient tcpportScan = new TcpClient(); 
     tcpportScan.SendTimeout = 10; 
     try 
     { 
      tcpportScan.Connect(txtIPaddress.Text, currPort); 
      txtDisplay.AppendText("Port " + currPort + " open.\n"); 
     } 
     catch (Exception) 
     { 
      txtDisplay.AppendText("Port " + currPort + " closed.\n"); 
     } 
     progressBar1.PerformStep(); 
    } 
} 

有誰知道如何加速這一進程?

回答

1

以下C#4代碼將掃描並行端口和每當掃描中的一個完成通知UI。

ScanSinglePortTask方法執行每次掃描,ScanSinglePortTask方法開始掃描並返回字符串結果並顯示消息。每個任務都以LongRunning選項開始,以通知運行時並行運行大量任務是可以的,因爲每個操作都需要很長時間。

每次掃描後,在UI線程上運行的新任務將使用TaskScheduler.FromCurrentSynchronizationContext更新消息和進度欄。

ToArray調用對強制枚舉LINQ查詢並啓動任務是必需的。任務數組可以與Task.Factory.ContinueWhenAll一起使用,以在掃描完成後運行其他代碼,例如。 ?更新繁忙指示

private void ScanP() 
    { 
     int startPort = Convert.ToInt32(txtFrom.Text); 
     int endPoint = Convert.ToInt32(txtTo.Text); 

     progressBar1.Value = 0; 
     progressBar1.Maximum = endPoint - startPort + 1; 


     var scans = from i in Enumerable.Range(startPort, 
               endPoint - startPort + 1) 
        select ScanSinglePortTask(i) 
         .ContinueWith(t => Report(t.Result), 
          TaskScheduler.FromCurrentSynchronizationContext()); 
     var tasks=scans.ToArray(); 

    } 

    private Task<string> ScanSinglePortTask(int currPort) 
    { 
     return Task.Factory.StartNew(() => 
      { 
       try 
       { 
        using (var tcpportScan = new TcpClient()) 
        { 
         tcpportScan.SendTimeout = 10; 
         tcpportScan.Connect(txtIPaddress.Text, (int) currPort); 
        } 
        return "Port " + currPort + " open.\n"; 
       } 
       catch (Exception) 
       { 
        return "Port " + currPort + " closed.\n"; 
       } 
      }, TaskCreationOptions.LongRunning); 
    } 

    private void Report(object message) 
    { 
     txtDisplay.AppendText((string)message); 
     progressBar1.PerformStep(); 
    } 
+0

這幾乎完美:D!我編輯了代碼,以便將每個打開和關閉的端口放入一個字符串列表中。這是完美的工作,但我唯一的問題是,進度條沒有更新後,他發現第一個開放端口:(。對此有什麼想法?謝謝! –

+0

好的。我們需要在Connect()成功後調用Close() ? – Muthukkumaran

+0

否Close()由TcpClient.Dispose()調用。 –

2

在請求被視爲失敗之前創建連接會受到超時,這就是您的scannig如此之慢的原因。使用異步代碼和/或多線程來加快速度。

+0

如何做到這一點:(任何例子 –

+0

您的問題是,如果有人知道熱,使其更快,沒有;?) - 不管怎麼說,如果谷歌的關鍵字,你應該找什麼您正在尋找。我首先使用['Socket.BeginConnect'](http://msdn.microsoft.com/en-us/library/system.net.sockets.socket.beginconnect.aspx)代替'TcpClient'(這是Socket類的一個包裝),可能已經解決了這個問題。 – Lucero

+0

我想你已經把我帶到了正確的道路上,謝謝:D! –

0

嘗試使用parallel.foreach/for循環。這會快很多。

Parallel.For(0, 100, d => 
    { 
     // Do processing here 
     // d is the equivalent to i in a standard for loop    
    }); 



    List<int> numbers = new List<int>(); 
    Parallel.ForEach(numbers, n => 
     { 
     // Do Processing here 
     // n is the current item 
    }); 

這裏是一個鏈接到我的博客與一些更多的細節。

http://tsells.wordpress.com/2011/03/03/using-parallel-for-and-foreach-loops-in-net-4-2/

+0

可能值得一提的是,不同的項目可能(而且將會)在不同的線程中運行 - 你必須正確地鎖定你的可變數據結構(比如數字列表你的例子),並編組到UI線程用於更新進度條(如在OP示例中) – Lucero

+0

@Lucero在使用PLINQ時不需要鎖定數字PLINQ將數據分成數字並將每個分區分配給不同的線程處理 –

+0

並行問題。對於/ Foreach來說,它們不適合網絡IO等長時間運行的任務,並且會導致未充分利用。 –