2012-01-19 6 views
8

Possiedo un'app che esegue il ping tra l'intervallo IP o IP. Il problema è che quando gli host sono chiusi, il ping richiede più tempo di quanto non siano aperti. Quando l'host è chiuso, il tempo per il ping è di circa 1-2 secondi.Come eseguire un ping più veloce quando raggiungo un IP non raggiungibile?

Come posso rendere più veloce quando gli host sono chiusi?

Questo è il mio codice:

using System; 
using System.Text; 
using System.Windows.Forms; 
using System.Net.NetworkInformation; 

namespace Range_Pinger 
{ 
    public partial class PingIPRange : Form 
    { 
     uint startIP, endIP, currentIP; 
     int count = 0; 
     int open = 0; 
     int closed = 0; 

     public PingIPRange() 
     { 
      InitializeComponent(); 

      tmrPingInterval.Tick += new EventHandler(tmrPingInterval_Tick); 
     } 

     void tmrPingInterval_Tick(object sender, EventArgs e) 
     { 
      if (txtTo.Text == string.Empty) Ping(ip2str(startIP)); 
      else 
      { 
       if (currentIP >= endIP) tmrPingInterval.Stop(); 
       Ping(ip2str(currentIP)); 
       currentIP++; 
      } 

      count++; 

      tsslPingCount.Text = "Total number of pings: " + count.ToString() + 
       " Open IPs: " + open.ToString() + " Closed IPs: " + closed.ToString(); 
     } 

     static uint str2ip(string ip) 
     { 
      string[] numbers = ip.Split('.'); 

      uint x1 = (uint)(Convert.ToByte(numbers[0]) << 24); 
      uint x2 = (uint)(Convert.ToByte(numbers[1]) << 16); 
      uint x3 = (uint)(Convert.ToByte(numbers[2]) << 8); 
      uint x4 = (uint)(Convert.ToByte(numbers[3])); 

      return x1 + x2 + x3 + x4; 
     } 

     static string ip2str(uint ip) 
     { 
      string s1 = ((ip & 0xff000000) >> 24).ToString() + "."; 
      string s2 = ((ip & 0x00ff0000) >> 16).ToString() + "."; 
      string s3 = ((ip & 0x0000ff00) >> 8).ToString() + "."; 
      string s4 = (ip & 0x000000ff).ToString(); 

      return s1 + s2 + s3 + s4; 
     } 


     private void btnPing_Click(object sender, EventArgs e) 
     { 
      txtDisplay.Text = string.Empty; 
      tsslPingCount.Text = string.Empty; 
      count = 0; 
      open = 0; 
      closed = 0; 
      tmrPingInterval.Interval = int.Parse(nudInterval.Value.ToString()); 

      try 
      { 
       startIP = str2ip(txtFrom.Text); 
       if (txtTo.Text != string.Empty) endIP = str2ip(txtTo.Text); 
       currentIP = startIP; 
       tmrPingInterval.Start(); 
      } 
      catch 
      { 
       MessageBox.Show("Invalid input. It must be something like: 255.255.255.255"); 
      } 
     } 

     private void btnStop_Click(object sender, EventArgs e) 
     { 
      tmrPingInterval.Stop(); 
     } 

     private void Ping(string address) 
     { 
      Ping pingSender = new Ping(); 
      PingOptions options = new PingOptions(); 
      options.DontFragment = true; 
      string data = ""; 
      byte[] buffer = Encoding.ASCII.GetBytes(data); 
      int timeout = 120; 
      try 
      { 
       PingReply reply = pingSender.Send(address, timeout, buffer, options) ; 
       if (reply.Status == IPStatus.Success) 
       { 
        open++; 
        txtDisplay.AppendText("Host " + address + " is open." + Environment.NewLine); 
       } 
       else 
       { 
        closed++; 
        txtDisplay.AppendText("Host " + address + " is closed." + Environment.NewLine); 
       } 
      } 
      catch (Exception ex) 
      { 
       txtDisplay.SelectedText += Environment.NewLine + ex.Message; 
      } 
     } 

     private void tsmiExit_Click(object sender, EventArgs e) 
     { 
      this.Close(); 
     } 
    } 
} 

Questo è quello che ho adesso:

[DllImport("iphlpapi.dll", ExactSpelling = true)] 
    public static extern int SendARP(IPAddress DestIP, int SrcIP, byte[] pMacAddr, ref uint PhyAddrLen); 

    private void Ping(IPAddress address) 
    { 
     byte[] macAddr = new byte[6]; 
     uint macAddrLen = (uint)macAddr.Length; 

     if (SendARP(address, 0, macAddr, ref macAddrLen) == 0) 
     { 
      txtDisplay.AppendText("Host " + address + " is open." + Environment.NewLine); 
     } 
     else txtDisplay.AppendText("Host " + address + " is closed." + Environment.NewLine); 
    } 
+6

Che cos'è un host chiuso? Inoltre, perché non impostare il timeout come 2 secondi anziché 120? – leppie

+0

@leppie, dicendo host chiuso intendevo che l'IP non risponde al ping o è inattivo. Il cambio del timeout non cambia nulla. Ho provato. – HelpNeeder

+0

A cosa hai cambiato il timeout? – leppie

risposta

10

Non si dovrebbe ridurre il timeout. Prova a inviare più ping contemporaneamente asincroni.

var ping = new Ping(); 
ping.PingCompleted += (sender, eventArgs) => 
{ 
    // eventArgs.Reply.Address 
    // eventArgs.Reply.Status 
}; 
ping.SendAsync(ip, etc.); 
2

Non sono sicuro se this is any help (vedi post finale sul filo), sembra un problema quasi identico. Ciò a cui stai andando incontro è il timeout dello stack del protocollo. Puoi muoverti se usi la presa per connetterti, poiché avrai più controllo.

3

È necessario riprogettare l'applicazione per utilizzare il multithreading -> attività. Emettere un'attività per ogni ping e quando si riceve una risposta da un determinato host, attivare un evento e aggiornare l'interfaccia utente. Cambiare il timeout del socket ti aiuterà solo a ridurre il timeout da oltraggioso a insopportabile.

+0

Immagino che questo possa essere fatto, ma non ho fatto molto threading in C#. qualsiasi soluzione più semplice ? – HelpNeeder

+1

@HelpNeeder: usa il metodo che usi ora. Se lo vuoi "più veloce" allora devi usare più thread. –

6

Il tuo indirizzo è un string. Quindi passerà prima tramite DNS per vedere se questo è probabilmente un nome host (anche se si tratta di un indirizzo IP).

Suggerisco di utilizzare il sovraccarico prendendo uno IPAddress.

+0

Buon punto. Lo cambierò. – HelpNeeder

4

Ho creato uno scanner host dal vivo non molto tempo fa. Usa ARP per verificare se un computer è online. Una richiesta ARP è molto più veloce che se si eseguisse il ping di un host. Ecco il codice che ho usato per controllare se un host è disponibile:

//You'll need this pinvoke signature as it is not part of the .Net framework 
[DllImport("iphlpapi.dll", ExactSpelling = true)] 
public static extern int SendARP(int DestIP, int SrcIP, 
           byte[] pMacAddr, ref uint PhyAddrLen); 

//These vars are needed, if the the request was a success 
//the MAC address of the host is returned in macAddr 
private byte[] macAddr = new byte[6]; 
private uint macAddrLen; 

//Here you can put the IP that should be checked 
private IPAddress Destination = IPAddress.Parse("127.0.0.1"); 

//Send Request and check if the host is there 
if (SendARP((int)Destination.Address, 0, macAddr, ref macAddrLen) == 0) 
{ 
    //SUCCESS! Igor it's alive! 
} 

Se siete interessati Nmap also uses this technique per la ricerca di host disponibili.

ARP scan inserisce Nmap e i suoi algoritmi ottimizzati per le richieste ARP. E se riceve una risposta, Nmap non ha nemmeno bisogno di preoccuparsi dei pacchetti di ping basati su IP poiché sa già che l'host è attivo. Questo rende la scansione ARP molto più veloce e più affidabile rispetto alle scansioni basate su IP. Così è fatto di default durante la scansione di host ethernet rilevati da Nmap su una rete ethernet locale. Anche se vengono specificati diversi tipi di ping (come -PE o -PS), Nmap usa invece ARP per qualsiasi target che si trova sulla stessa LAN.

EDIT:

Questo funziona solo all'interno della sottorete corrente! Finché non vi è alcun router tra la macchina richiedente e la destinazione, dovrebbe funzionare correttamente.

ARP è un protocollo non instradabile e può quindi essere utilizzato solo tra sistemi sulla stessa rete Ethernet. [...] arp-scan può essere utilizzato per scoprire gli host IP sulla rete locale. Può scoprire tutti gli host, compresi quelli che bloccano tutto il traffico IP come firewall e sistemi con filtri di ingresso.- Excerpt from NTA-Monitor wiki

Per ulteriori informazioni sulla funzione SendARP è possibile controllare la documentazione pinvoke.net.

+0

Ho appena corretto il codice. La riga 7 era -> (int) this.Destination.Address anche se doveva essere (int) Destination.Address Ho copiato il codice da un progetto che utilizzava i thread in modo da spiegare l'errore :) – SanBen

+0

Bene, per alcuni motivo per cui ottengo sempre risultati falsi. anche su indirizzi ip vivi. – HelpNeeder

+1

Ho aggiunto il codice che ho al mio OP qui. – HelpNeeder

Problemi correlati