2 votes

Découvrez tous les appareils sur le réseau local

Dans mon application Xamarin Forms, j'essaie de découvrir tous les appareils sur le réseau local auquel je suis connecté. Ma démarche est d'abord d'obtenir l'adresse IP de l'appareil, puis d'utiliser les trois premiers nombres pour connaître quelle est la passerelle (le premier nombre est toujours 192). Ensuite, je ping chaque adresse sur cette passerelle. Voici mon code :

public partial class MainPage : ContentPage
{
    private List<Device> discoveredDevices = new List<Device>();

    public MainPage()
    {
        InitializeComponent();

        Ping_all();
    }

    private string GetCurrentIp()
    {
        IPAddress[] addresses = Dns.GetHostAddresses(Dns.GetHostName());
        string ipAddress = string.Empty;
        if (addresses != null && addresses[0] != null)
        {
            ipAddress = addresses[0].ToString();
        }
        else
        {
            ipAddress = null;
        }

        return ipAddress;
    }

    public void Ping_all()
    {
        string ip = GetCurrentIp();

        if (ip != null)
        {
            //Extraction et ping de toutes les autres adresses IP.
            string[] array = ip.Split('.');
            string gateway = array[0] + "." + array[1] + "." + array[2];

            for (int i = 2; i <= 255; i++)
            {
                string ping_var = $"{gateway}.{i}";

                //Temps en millisecondes           
                Ping(ping_var, 4, 4000);
            }
        }
    }

    public void Ping(string host, int attempts, int timeout)
    {
        for (int i = 0; i < attempts; i++)
        {
            new Thread(delegate ()
            {
                try
                {
                    System.Net.NetworkInformation.Ping ping = new System.Net.NetworkInformation.Ping();
                    ping.PingCompleted += new PingCompletedEventHandler(PingCompleted);
                    ping.SendAsync(host, timeout, host);
                    // PingCompleted n'est jamais appelé
                }
                catch(Exception e)
                {
                    // Ne rien faire et laisser essayer à nouveau jusqu'à ce que les tentatives soient épuisées.
                    // Les exceptions sont lancées pour des échecs de ping normaux comme l'échec de la recherche d'adresse.
                    // Pour cette raison, nous supprimons les erreurs.
                }
            }).Start();
        }
    }

    private void PingCompleted(object sender, PingCompletedEventArgs e)
    {
        string ip = (string)e.UserState;
        if (e.Reply != null && e.Reply.Status == IPStatus.Success)
        {
            string hostname = GetHostName(ip);
            string macaddres = GetMacAddress(ip);

            var device = new Device()
            {
                Hostname = hostname,
                IpAddress = ip,
                MacAddress = macaddres
            };

            discoveredDevices.Add(device);
        }
    }

    public string GetHostName(string ipAddress)
    {
        try
        {
            IPHostEntry entry = Dns.GetHostEntry(ipAddress);
            if (entry != null)
            {
                return entry.HostName;
            }
        }
        catch (SocketException)
        {

        }

        return null;
    }

    public string GetMacAddress(string ipAddress)
    {
        string macAddress = string.Empty;
        System.Diagnostics.Process Process = new System.Diagnostics.Process();
        Process.StartInfo.FileName = "arp";
        Process.StartInfo.Arguments = "-a " + ipAddress;
        Process.StartInfo.UseShellExecute = false;
        Process.StartInfo.RedirectStandardOutput = true;
        Process.StartInfo.CreateNoWindow = true;
        Process.Start();
        string strOutput = Process.StandardOutput.ReadToEnd();
        string[] substrings = strOutput.Split('-');
        if (substrings.Length >= 8)
        {
            macAddress = substrings[3].Substring(Math.Max(0, substrings[3].Length - 2))
                     + "-" + substrings[4] + "-" + substrings[5] + "-" + substrings[6]
                     + "-" + substrings[7] + "-"
                     + substrings[8].Substring(0, 2);
            return macAddress;
        }
        else
        {
            return "Machine Propre";
        }
    }
}

J'arrive à la partie où j'essaie de pinguer :

System.Net.NetworkInformation.Ping ping = new System.Net.NetworkInformation.Ping();
ping.PingCompleted += new PingCompletedEventHandler(PingCompleted);
ping.SendAsync(host, timeout, host);

Mais PingCompleted n'est jamais appelé. Aucune exception n'est lancée non plus. Une idée pourquoi ? Je lance ceci sur un appareil Android physique.

MODIFICATION

PingCompleted commence à être appelé maintenant, je ne sais pas pourquoi ça ne fonctionnait pas avant. Mais ça plante maintenant dans ma fonction GetMacAddress sur la ligne Process.Start(); car il ne trouve pas la ressource.

1voto

Darius Points 514

J'ai fini par utiliser cette bibliothèque vraiment robuste et facile à utiliser :

https://github.com/Yortw/RSSDP

En fait, elle ne trouve pas tous les appareils sur le réseau, mais utilise plutôt SSDP (Simple Search Discovery Protocol) pour rapidement trouver tous les appareils qui diffusent un service avec ce protocole sur le réseau. Je l'ai filtrée pour ne scanner que les appareils exécutant mon application, ce dont j'avais vraiment besoin. Il ne prend qu'une seconde pour découvrir mes appareils, ce qui est beaucoup plus rapide que de pinguer 255 adresses.

Dans la documentation, vous verrez :

var deviceDefinition = new SsdpRootDevice()
{
    CacheLifetime = TimeSpan.FromMinutes(30), //Combien de temps les clients SSDP peuvent mettre en cache ces infos.
    Location = new Uri("http://mydevice/descriptiondocument.xml"), // Doit pointer vers l'URL qui fournit le document de description UPnP de vos appareils. 
    DeviceTypeNamespace = "my-namespace",
    DeviceType = "MyCustomDevice",
    FriendlyName = "Custom Device 1",
    Manufacturer = "Me",
    ModelName = "MyCustomDevice",
    Uuid = GetPersistentUuid() // Cela doit être une valeur globalement unique qui survit aux redémarrages, etc. Récupérez-la depuis le stockage ou le matériel intégré, etc.
};

Pour le Location, je l'ai configuré avec l'IP de mon appareil. Ainsi un autre appareil qui le découvre peut aussi avoir l'IP. Je ne pense pas que ce soit censé être utilisé de cette manière, mais cela a fonctionné pour moi et je ne vois pas pourquoi ça ne marcherait pas.

Je l'ai testé sur 2 appareils Android physiques.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X