2017-02-03 3 views
3

J'essaie de créer une application qui analyse un réseau pour les demandes ARP et répertorie tous les périphériques réseau existants. Actuellement, j'utilise SharpPcap et PacketDoNet.Prévention des exceptions lors de la résolution du nom d'hôte

Lors de la résolution du nom d'hôte en fonction de l'adresse IP donnée, j'obtiens un SocketException lors de la résolution d'un hôte "inconnu". J'ai donc mis ceci dans un essai/catch. Puisque je pense que c'est un mauvais style (pour ignorer les exceptions), je cherche une solution différente.

Voici un code:

// Button for scanning the network 
private void btnStartScanningForClients_Click(object sender, RoutedEventArgs e) 
{ 
    // Check for correct interface 
    // [...] 

    // Start scanning process 
    if (!this.netWorkItOut.Startet) 
    { 
     // Dis-/Enable visual controls 
     // [...] 

     // Start scanning 
     var index = this.cbNetworkInterface.SelectedIndex 
     this.netWorkItOut.StartDevice(index); 
     this.netWorkItOut.Scanner.StartScanningNetwork(resolveHostnames); 
    } 
} 

Ceci est l'objet de contrôle, qui détient le scanner, prend en charge des événements, accepte les paquets et les met dans une file d'attente

public void StartDevice(int deviceIndex) 
{ 
    this.Startet = true; 
    // [...] 
    this.Device = WinPcapDeviceList.Instance[deviceIndex]; 

    // Activate Scanner 
    this.Scanner = new Scanner(this.DeviceInfo); 

    // Subscribe Events 
    // [...] 

    this.Device.Open(DeviceMode.Promiscuous, 1); 
    this.Device.Filter = "(arp || ip || ip6)"; 

    this.Device.OnPacketArrival += device_OnPacketArrival; 
    this.Device.StartCapture(); 
} 

private void device_OnPacketArrival(object sender, CaptureEventArgs e) 
{ 
    //PacketDoNet 
    Packet packet; 

    try 
    { packet = Packet.ParsePacket(LinkLayers.Ethernet, e.Packet.Data); } 
    catch (Exception) 
    { return; } 

    if (packet is EthernetPacket) 
    { 
     var arp = ARPPacket.GetEncapsulated(packet); 

     if (arp != null) 
     { 
      if (this.Scanner.Started) 
      { 
       lock (this.Scanner.PacketQueueARP) 
       { 
        this.Scanner.PacketQueueARP.Add(arp); 
       } 
      } 
     } 
    } 
} 

C'est Contrôle de l'objet et de la classe Scanner. La classe du scanner fonctionne les requêtes ARP et résout le hostname

public void StartScanningNetwork(bool resolveHostnames) 
{ 
    // [...] 
    this.ResolveHostnames = resolveHostnames; 

    // start worker to listen for ARP packets 
    this.workerARP = new Thread(WorkerARP); 
    this.workerARP.Name = "Scanner thread (ARP)"; 
    this.workerARP.Start(); 

    this.Started = true; 
} 

private void WorkerARP() 
{ 
    List<IPAddress> processedIps = new List<IPAddress>(); 

    // copy packets from storage queue to thread queue for processing 
    while (Started) 
    { 
     // [...] 

     if (this.threadQueueARP.Count > 0) 
     { 
      foreach (var packet in this.threadQueueARP) 
      { 
       // [...] 

       if (!processedIps.Contains(ip)) 
       { 
        // [...] 

        if (this.ResolveHostnames) 
        { 
         var resolveHostnamesTask = Task.Factory.StartNew(ResolveHostnamesWorker, ip); 
        } 
       } 
       // [...] 
      } 

      // [...] 
     } 
     // [...] 
    } 

} 

private void ResolveHostnamesWorker(object data) 
{ 
    if (data is IPAddress) 
    { 
     var ip = (IPAddress)data; 
     var hostname = ""; 

     try 
     { 
      hostname = Dns.GetHostEntry(ip).HostName; 
     } 
     catch { } 

     // Raise Event for hostname resolved 
    } 
} 

Son tout sur la ligne hostname = Dns.GetHostEntry(ip).HostName

donc: Comment puis-je éviter d'utiliser un try/catch pour résoudre un HostEntry via Dns.GetHostEntry()? Y a-t-il une fonction qui renvoie simplement null s'il n'y a pas d'hôte connu?

Merci d'avance! Pour autant que je sache, il n'y a pas de méthode comme TryGetHostName() qui ne déclencherait pas d'exception.

Répondre

1

Mais à mon avis, il est lisible d'attraper des exceptions aussi loin que vous les attendez. Donc, vous devez limiter la capture des exceptions à ceux que vous attendez:

private void ResolveHostnamesWorker(object data) 
{ 
    if (data is IPAddress) 
    { 
     var ip = (IPAddress)data; 
     var hostname = ""; 

     try 
     { 
      hostname = Dns.GetHostEntry(ip).HostName; 
     } 
     catch(SocketException socketException) 
     { 
      // maybe limit handling based on data in socketException and 
      // call throw; to rethrow exception if not the expected one 
     } 

    // Raise Event for hostname resolved 
} 

}

+0

étant donné que la capture d'exceptions est un processus fastidieux, cela devrait être ma dernière option. Mais s'il n'y a pas d'autre moyen, je dois le faire de cette façon. Merci pour votre réponse! – Radinator

3

Comme le code de la classe Dns est disponible sous https://github.com/Microsoft/referencesource/blob/master/System/net/System/Net/DNS.cs vous pouvez utiliser à partir de là que la partie concernée. (Bien sûr, vous devez vérifier si la licence MIT peut être utilisée dans votre projet)

L'implémentation est dans la méthode InternalGetHostByAddress où les exceptions sont levées. Là, vous pouvez simplement retourner une valeur (bool, enum ...) pour fournir des informations si la requête a réussi.

+0

Ce fut la première chose que j'ai essayé après avoir posté la question ... honte à moi ... – Radinator