Speed up scanning network

JackilionJackilion DEMember ✭✭

Hi everyone,

I'm doing a pet project, where I want to connect my smartphone to my raspberry Pi. The server is written in .NET Core 2.0 and the app with Xamarin Forms.
Now, My Raspberry Pi does not have a constant IP Address, everytime I restart my router, it'll change. So what I'm currently doing, is pinging every address (from 192.168.2.1 to 192.168.2.255) to check which addresses are currently used, and then try to connect through my servers port and see which of the active devices is my raspberry.

class NetworkSearcher
    {
        /// <summary>
        /// Base IP which to search. E.g. 192.168.1. to search from 192.168.1.0 to 192.168.1.255
        /// </summary>
        public string BaseIP { get; set; }
        public int TTL { get; set; } = 64;
        /// <summary>
        /// Timeout in miliseconds.
        /// </summary>
        public int TimeOut { get; set; } = 1000;

        private object @lock = new object();
        private int instances = 0;
        private List<Ping> pingList = new List<Ping>();
        private List<string> activeIPs = new List<string>();

        public NetworkSearcher() : this("192.168.1.") { }
        public NetworkSearcher(string BaseIP)
        {
            this.BaseIP = BaseIP;   
        }

        public List<string> SearchForActiveIPs()
        {
            CreatePings(255);
            var po = new PingOptions(TTL, true);
            var encoding = new ASCIIEncoding();
            byte[] data = encoding.GetBytes("abababababababababababababababab");
            SpinWait wait = new SpinWait();
            int counter = 1;

            foreach (var p in pingList)
            {
                lock (@lock)
                {
                    instances += 1;
                }
                p.SendAsync(string.Concat(BaseIP, counter.ToString()), TimeOut, data, po);
                counter++;
            }
            while (instances > 0)
            {
                wait.SpinOnce();
            }
            DestroyPings();
            return activeIPs;
        }
        private void CreatePings(int count)
        {
            for (int i = 1; i <= count; i++)
            {
                var p = new Ping();
                p.PingCompleted += OnPingCompleted;
                pingList.Add(p);
            }
        }
        private void OnPingCompleted(object sender, PingCompletedEventArgs args)
        {
            lock (@lock)
            {

                if (args.Reply.Status == IPStatus.Success)
                {
                    activeIPs.Add(args.Reply.Address.ToString());
                }
                instances -= 1;
            }
        }
        private void DestroyPings()
        {
            foreach (var ping in pingList)
            {
                ping.PingCompleted -= OnPingCompleted;
                ping.Dispose();
            }
            pingList.Clear();
        }
    }

This returns me a list of active devices. Now, on my laptop (which is rather old), identifying my raspberry Pi takes around 1300ms. But On my Xamarin Forms app, it takes 38(!) seconds! This must be fixable, because I don't believe that my Samsung Galaxy S8 is that slow.

For my app, I wrapped this process like this:

private async Task ExecuteScanCommandAsync()
        {
            serverConnector = ServerConnector.Instance;
            IsBusy = true;
            var success = await Task.Run(() => serverConnector.EstablishConnection());
            OnScanCompleted(success);

        }

The ServerConnector saves information about the raspberry for later communication. It calls the network search likes this:

public async Task<bool> EstablishConnection()
        {
            //Get the base ip of the network:
            var ipHostEntry = await Dns.GetHostEntryAsync(Dns.GetHostName());
            var myAddress = ipHostEntry.AddressList[0].ToString();
            var baseIp = myAddress.Substring(0, myAddress.LastIndexOf('.')) + ".";
            //Identify Server
            var serverIdentifier = new ServerIdentifier();

            var serverAddress = await Task.Run(() => serverIdentifier.Identify(baseIp));

            if (serverAddress == "") //Server not online.
                return false;

            this.serverAddress = serverAddress;
            return true;
        }

The method serverIdentifier.Identify(baseIp); directly calls my network searcher. And thanks to the stopwatch I know that this is the part that takes the 38 seconds.

Any suggestions how to speed up this process? It starts around 16 threads while searching.

Answers

  • LandLuLandLu Member, Xamarin Team Xamurai

    This may be device related, have you tested it on another device? Also why not make your server device use a fixed IP? In this way, there's no need to search your server's IP every time you want to connect to it.

  • JackilionJackilion DEMember ✭✭

    No, I only tested it on my own Smartphone. However, it is an Samsung Galaxy S8, which is already fairly high-end. I might test it on my girlfriends iPhone later.
    Of course I could change the settings in my router to just avoid this problem. However, this seems "unclean" to me. As this is just my hobby, I want to settle for an elegant solution.
    Still, you're right, there's no need to search the network every time. I'll save the servers IP for later starts and ping this address first. Only if it's not the correct one, I'll search the whole network.

    Still, I'd appreciate suggestions to speed it up a little.

Sign In or Register to comment.