2016-05-26 4 views
0

Ich habe Probleme mit WaitAll in der unteren Code. Diese Methode empfängt eine Liste von IP-Adressen und einen Port (ich scanne nach WMI-Port 135) und gibt eine Liste von IP-Adressen zurück, bei denen der Port geöffnet ist. Ich glaube, ich habe WaitAll nicht korrekt implementiert, als wenn ich diesen Code verlangsame, scheint es die richtigen Systeme auszuführen und zurückzugeben. Vielen Dank.Threading-Aufgaben zum Scannen öffnen TCP-Port

private static List<IPAddress> openSystems = new List<IPAddress>(); 

public static List<IPAddress> Scan(List<IPAddress> addresses, ushort port) 
{ 
    int count = addresses.Count; 
    Task[] tasks = new Task[count]; 

    //Loop through ip address 
    for(int x = 0; x <= count -1; x++) 
    { 
     tasks[x] = Task.Factory.StartNew(() => 
     { 
      using (TcpClient tcp = new TcpClient()) 
      { 
       try 
       { 
        Console.WriteLine("Trying to get into {0}", addresses[x]); 
        tcp.Connect(addresses[x], port); 
        openSystems.Add(addresses[x]); 
       } 
       catch 
       { 
        Console.WriteLine("Can't get into {0}", addresses[x]); 
        //ignore exceptions 
       } 
      } 
     }); 
    } 

    Task.WaitAll(tasks); 
    return openSystems; 
} 
+2

Also, was ist das Problem? Und wie "verlangsamen Sie den Code"? Außerdem benötigen Sie eine 'lock' um' openSystems.Add (Adressen [x]) '' oder verwenden Sie eine der ['concurrent collections'' (https://msdn.microsoft.com/en-us/library/system .collections.concurrent (v = vs.110) .aspx) – Quantic

+0

Ignoriert Exceptions _always_ immer eine schlechte Idee? –

Antwort

1

Es gibt mehrere Best Practices, die in Ihrem Code ignoriert werden.

Sie sollten die ConnectAsync Methode des TcpClient nennen und zu Task.Factory.StartNew des Anrufs loszuwerden

Sie nicht Task.WaitAll verwenden sollten aber await Task.WhenAll

Die Methodensignatur wird dann public static Task> ScanAsync(List addresses, ushort port) und man kann erwarten, dass in dem codieren wird genannt.

Sie greifen auf die Liste openSystems für verschiedene Threads zu. Liste ist nicht threadsafe, also sollten Sie eine gleichzeitige Sammlung verwenden oder es andernfalls tun.

public static async Task<List<IPAddress>> ScanAsync(List<IPAddress> addresses, ushort port) 
{ 
    var tasks = addresses.Select(a => CheckIpAsync(a, port); 

    await Task.WhenAll(tasks); 
    return openSystems; 
} 

private async Task CheckIpAsync(IPAddress address, ushort port) 
{ 
    using (TcpClient tcp = new TcpClient()) 
    { 
     try 
     { 
      Console.WriteLine("Trying to get into {0}", address); 
      await tcp.ConnectAsync(address, port); 
      openSystems.Add(address); 
     } 
     catch 
     { 
      Console.WriteLine("Can't get into {0}", address); 
      //ignore exceptions 
     } 
    } 
} 

Das könnte Ihre Frage immer noch nicht beantworten, da ich keine finden kann. Aber es zeigt eine bessere Implementierung.

+0

Danke für Ihre Hilfe. Ich bin mit den Best Practices nicht vertraut. Ich verstehe nicht ganz, warum ScanAsync ein Task-Typ ist. Ich kann openSystems nicht zurückgeben. Ich habe Probleme mit der Zeile "Warten auf Task.WhenAll (Aufgaben)" in Ihrem Code und gibt auch openSystems zurück. Danke, dass Sie darauf hingewiesen haben, dass ich keine gleichzeitige Sammlung verwende. Würden Sie ein gleichzeitiges Wörterbuch für diese Daten empfehlen? –

+0

@JoshuaEllis sorry Ich habe einen wichtigen Teil vergessen, ich habe meine Antwort aktualisiert. Ich nehme an, dass die Probleme, die Sie hatten, dass der Code in meiner Antwort nicht kompiliert wurde. –

+0

Da wir in CheckIpAsync eine Warteanweisung haben, muss eine Task zurückgegeben werden. Mit dem Code der Antwort brauchen Sie keine gleichzeitige Sammlung, da wir die Liste in einem anderen Thread nicht aktualisieren. Eine Erläuterung zu async/await finden Sie unter https://msdn.microsoft.com/en-us/library/mt674882.aspx. Es ist von grundlegender Bedeutung, die Grundlagen zu verstehen, bevor Sie einen aufgabenbezogenen Code verwenden. –