Laden...

IP Scanner- Geschwindigkeit optimieren

Erstellt von Pico1184 vor 11 Jahren Letzter Beitrag vor 11 Jahren 4.630 Views
Pico1184 Themenstarter:in
223 Beiträge seit 2009
vor 11 Jahren
IP Scanner- Geschwindigkeit optimieren

Hallo,

ich benötige für meine Software einen IP Scanner für das automatische Erkennen von Automatisierungsgeräten im Netzwerk.

Nun dachte ich, dass ich es folgendermaßen angehe:

  • IP Adresse des lokalen Rechner ermitteln
  • Schleife von 0 - 255 durchlaufen lassen
  • das 4 Oktett anpassen (0-255)
  • Ping absenden
  • auswerten
  • falls Ping erfolgreich Connect durchführen um auf mein bestimmtes Gerät zu prüfen

folgendermaßen sieht das aus:


 public IEnumerable<Connectors> BrowseConnector(string ipAdress)
        {
            var tempConfig = new PLCConnectionConfiguration("tempConfig");
            var tempConn = new PLCConnection(tempConfig);
            var ipSub = ipAdress.Split('.');
            var connectors = new List<Connectors>();

            for (var i = 0; i <= 255; i++)
            {
                ipSub[3] = Convert.ToString(i);
                var nextIp = String.Join(".", ipSub);

                if (!IpScanner.Ping(nextIp, 1, 80)) continue;
                tempConfig.CpuIP = nextIp;
                try
                {
                    tempConn.Connect();
                    var connector = new Connectors { RemoteName = nextIp };
                    connectors.Add(connector);
                    tempConn.Disconnect();
                }
                catch (Exception)
                {
                    continue;
                }
            }
            return connectors;
        }


  public static bool Ping(string host, int attempts, int timeout)
        {
            var ping = new Ping();

            for (int i = 0; i < attempts; i++)
            {
                try
                {
                    PingReply pingReply = ping.Send(host, timeout);

                   if (pingReply != null &&
                        pingReply.Status == IPStatus.Success)
                        return true;
                }
                catch
                {
                    
                }
            }
           
            return false;
        }
    }

Nun dauert dies allerdings so ca. 2,5 Minuten bis das ganze Segment durchgelaufen ist.
Das ist ja keinem zumutbar.
Habt ihr noch ne Idee wie man hier die Geschwindigkeit optimieren kann??

Grüße Pico

C
40 Beiträge seit 2011
vor 11 Jahren

Hallo Pico1184,

dein Ping timeout ist ja schon recht niedrig gesetzt. Bist du sicher das nicht evtl.

tempConn.Connect();

einen viel höheren timeout besitzt, der die Laufzeit negativ beeinträchtigt?

Zudem fällt mir noch folgendes auf:

  • Das pingen auf 0 und 255 würde ich vermeiden. Dem Anschein nach ist 0 bei dir momentan Netzmaske und 255 Broadcast.
  • Splitte die Prüfung von PingReply in der Ping Methode auf. Falls PingReply null ist wird es beim Zugriff auf das Status Property knallen.
  • Wenn du die BrowseConnector Methode nicht spezialisiert planst, dann verarbeite die Subnetzmaske noch. Das Segment muss nicht zwingend von 1-254 reichen.

Gruß Chris

Pico1184 Themenstarter:in
223 Beiträge seit 2009
vor 11 Jahren

einen viel höheren timeout besitzt, der die Laufzeit negativ beeinträchtigt?

Da hast du schon recht! Das Connect hat einen viel höheren Timeout!
Aber ich denke auch, dass der Timeout beim Pingen zu klein ist, habe den nur mal zum testen verringert.
Timeout verringern löst also mein Problem nicht!

D.h. ich bin momentan ziemlich ratlos wie ich da die Performance verbessern kann!

  • Wenn du die BrowseConnector Methode nicht spezialisiert planst, dann verarbeite die Subnetzmaske noch. Das Segment muss nicht zwingend von 1-254 reichen.

Das könnte ich natürlich noch tun, aber in dem Netzwerk wo die Software eingesetzt wird ist die subnetzmaske immer 255.255.255.0

Aber du hast recht, so gehört das schon rein!

Grüße Pico

16.830 Beiträge seit 2008
vor 11 Jahren

Bei sowas bietet sichnes doch gerade zu an alles zu kodularisieren und zu parallelisieren...
Alles sequentiell zu halten ist doch logischerweise das langsamste, was man tun koennte.. 🤔

Pico1184 Themenstarter:in
223 Beiträge seit 2009
vor 11 Jahren

Bei sowas bietet sichnes doch gerade zu an alles zu kodularisieren und zu parallelisieren...

Da ich mit der TPL bisher noch nicht gearbeitet habe hatte ich mich noch nicht daran getraut.

Habe es nun aber mit einer Parallel.For Schleife probiert:


  public static IEnumerable<Connectors> BrowseConnector(string ipAdress)
        {                     
            var ipSub = ipAdress.Split('.');
            var connectors = new List<Connectors>();
            var localIpSubstring = String.Join(".", ipSub, 0, 3);          

            Parallel.For(1, 255, i =>
                {                   
                    var tempConfig = new PLCConnectionConfiguration("tempConfig" + i);
                    var tempConn = new PLCConnection(tempConfig);                                        
                    var nextIp = String.Concat(localIpSubstring, ".", Convert.ToString(i));
                                                       
                    if (!IpScanner.Ping(nextIp, 1, 500)) return;
                        tempConfig.CpuIP = nextIp;
                        Console.WriteLine("Found " + nextIp);
                        try
                        {
                            tempConn.Connect();
                            var connector = new Connectors { RemoteName = nextIp };
                            connectors.Add(connector);
                            tempConn.Disconnect();
                        }
                        catch (Exception)
                        {
                            Console.WriteLine(nextIp + " isn't a PLC");
                        }
                    }
                
                );          
            return connectors;
        }

Damit benötigt das Scannen für das ganze Segment nur noch ca. 20 sec.
Also ein enormer Unterschied.

Jetzt ist nur die Frage ob das auch alles so richtig programmiert ist oder ob es irgendwo Zugriffsprobleme geben kann???

Insbesondere stört es mich hier, dass ich bei jedem Schleifendurchgang ein neues PLCConfig Objekt und ein neues PLCConnection Objekt erstelle.

Grüße Pico

S
322 Beiträge seit 2007
vor 11 Jahren

Hallo Pico1184,

ich würde es so machen:


public static IEnumerable<Connectors> BrowseConnector(string ipAdress)
        {
            var ipSub = ipAdress.Split('.');
            var connectors = new List<Connectors>();
            var localIpSubstring = String.Join(".", ipSub, 0, 3);

            Parallel.For(1, 255, i =>
                {
                    var nextIp = String.Concat(localIpSubstring, ".", Convert.ToString(i));

                    if (IpScanner.Ping(nextIp, 1, 500))
                    {
                    	var tempConfig = new PLCConnectionConfiguration("tempConfig" + i);
                    	var tempConn = new PLCConnection(tempConfig);
                        tempConfig.CpuIP = nextIp;
                        Console.WriteLine("Found " + nextIp);
                        try
                        {
                            tempConn.Connect();
                            var connector = new Connectors { RemoteName = nextIp };
                            lock (connectors)
                            {
                            	connectors.Add(connector);
                            }
                            tempConn.Disconnect();
                        }
                        catch (Exception)
                        {
                            Console.WriteLine(nextIp + " isn't a PLC");
                        }
                    }

                );
            return connectors;
        }

bei der If-Abrage war das Return nicht angebracht, dies beendet die schleifen komplett... und wenn du diese temporäre Objekte nur anlegt wenn ping erfolgreich ist, dann dauert es evtl. nicht mehr soo lange...
Bei connectors.Add muss dieser Aufruf synchronisiert werden, damit die Liste nicht von mehreren Threads gleichzeitig verändert werden kann.

Evtl. würde es auch was bringen wenn du die Anzahl der Threads erhöhst da die meiste Zeit der Ping-Timeout benötigt:
http://msdn.microsoft.com/de-de/library/system.threading.threadpool.setmaxthreads%28v=VS.80%29.aspx

Pico1184 Themenstarter:in
223 Beiträge seit 2009
vor 11 Jahren

bei der If-Abrage war das Return nicht angebracht, dies beendet die schleifen komplett...

Das ist so nicht richtig, das Return beendet hier nur die Methode durch die Schleife wird sie aber wieder aufgerufen!


lock (connectors)
{
      connectors.Add(connector);
 }

oder


var lockObject = new Object();

lock (lockObject)
{
      connectors.Add(connector);
 }

Grüße Pico

S
322 Beiträge seit 2007
vor 11 Jahren

Hallo Pico,

wobei das lockObject dann außerhalb der Schleife deklariert sein muss.

Hast Du schon den Pinger versucht asynchron anzustoßen?
http://dotnet-snippets.de/dns/asynchrone-pingabfrage-ueber-pcs-in-der-domaine-SID1216.aspx

Ich habe soeben kurz angetestet, dort ist der Pinger kurz nach der Timeout-Zeit fertig...
Hier braucht man auch kein parallele Schleife mehr...

16.830 Beiträge seit 2008
vor 11 Jahren

Wenn man das ganze via TPL löst hat man den Vorteil, dass man sich quasi nicht um die Synchronisation kümmern muss. Bei der asynchronen Variante muss man auf alle Callbacks warten. Im Prinzip ist das nur Vorteilhaft, wenn man eben nicht auf den Abschluss ALLER Antworten warten muss.