0

I am in the process of creating an app that displays a list of IP addresses from my database. All of this is working great now with the help received from SO.

The only problem I face now is that I need it run continuously and display the results again in the UI (FlowLayout)

This is the code I have (from):
Retrieve data from SQL database and use dynamically created Labels to show Ping results

 public partial class frmMainWindow : Form
{
    public frmMainWindow()
    {
        InitializeComponent();
        Shown += frmMainWindow_Shown;
    }

    private void addToolStripMenuItem_Click(object sender, EventArgs e)
    {
        frmAddHosts nForm = new frmAddHosts();
        nForm.Show();
    }

    private async void frmMainWindow_Shown(object sender, EventArgs e)
    {
        var ipAddresses = new List<string>();
        var ipControls = new List<Control>();
        var font = new Font("Segoe UI", 20, FontStyle.Regular, GraphicsUnit.Pixel);

        string sql = "SELECT [host], [ip] FROM addhosts";
        string connString = @"Data Source=FCA-Keith\SQL;Initial Catalog=PingMonitorDB;Integrated Security=True";

        using (var conn = new SqlConnection(connString))
        using (var cmd = new SqlCommand(sql, conn))
        {
            await conn.OpenAsync();
            using (var reader = await cmd.ExecuteReaderAsync())
            {
                int ipCount = 0;
                while (await reader.ReadAsync())
                {
                    var lbl = new Label()
                    {
                        AutoSize = false,
                        BackColor = Color.LightGray,
                        ForeColor = Color.Black,
                        Font = font,
                        Name = $"lblAddress{ipCount}",
                        Size = new Size(flowLayoutPanel1.ClientSize.Width, font.Height + 4),
                        Text = $"{reader["host"]} {reader["ip"]} "
                    };
                    ipAddresses.Add(reader["ip"].ToString());
                    ipControls.Add(lbl);
                }
            }
        }

        // If the Reader returned some results, add the Control to a FlowLayoutPanel
        // and pass the list of addresses to MassPing, plus the Progress<T> delegate
        if (ipAddresses.Count > 0)
        {
            flowLayoutPanel1.Controls.AddRange(ipControls.ToArray());
            var massPing = new MassPing();
            var progress = SetPingProgressDelegate(ipControls);
            await massPing.PingAll(ipAddresses.ToArray(), progress, 2500);
        }
    }
    private IProgress<(int, object)> SetPingProgressDelegate(List<Control> uiControls)
    {
        var controls = uiControls;
        var obj = new object();

        // Create a Progress<T> delegate to receive status updates  
        // Each Task reports back here. This code is executed in the UI Thread
        var progress = new Progress<(int seq, object reply)>(report => {
            lock (obj)
            {
                var status = IPStatus.Unknown;
                var color = Color.Transparent;
                if (report.reply is PingReply pr)
                {
                    status = pr.Status;
                    color = status is IPStatus.Success
                        ? pr.RoundtripTime > 10 ? Color.LightGreen : Color.Yellow
                        : Color.OrangeRed;
                }
                else if (report.reply is SocketError socErr)
                {
                    if (socErr == SocketError.HostNotFound)
                    {
                        status = IPStatus.DestinationHostUnreachable;
                        color = Color.Red;
                    }
                }
                controls[report.seq].BackColor = color;
                controls[report.seq].Text += status.ToString();
            }
        });
        return progress;
    }
}

MassPing.cs

public class MassPing
{
    public async Task PingAll(string[] addresses, IProgress<(int seq, object reply)> progress, uint timeout = 2000)
    {
        var tasks = new List<Task>();

        // Add all tasks
        for (int seq = 0; seq < addresses.Length; seq++)
        {
            tasks.Add(PingAsync(addresses[seq], (int)timeout, seq, progress));
        }
        await Task.WhenAll(tasks);
    }

    private async Task PingAsync(string ipAddress, int timeOut, int sequence, IProgress<(int seq, object reply)> progress)
    {
        var buffer = new byte[32];
        var ping = new Ping();

        try
        {
            var options = new PingOptions(64, true);
            PingReply reply = await ping.SendPingAsync(ipAddress, timeOut, buffer, options);
            progress.Report((sequence, reply));
        }
        catch (PingException pex)
        {
            if (pex.InnerException is SocketException socEx)
            {
                progress.Report((sequence, socEx.SocketErrorCode));
            }
        }
        finally
        {
            ping.Dispose();
        }
    }
}

In the past I used to use a timer to achieve this but I don't think it will work so great with this?

Thanks

Jimi
  • 29,621
  • 8
  • 43
  • 61
  • Use the last code update in your previous question. – Jimi Aug 23 '21 at 08:14
  • Hi, it doesn't seem to be working :-( I checked that I typed everything correctly and when I run the app and disconnect a device it still says its online (getting a ping response) –  Aug 23 '21 at 10:53
  • Not with this code. This is run once when the Form is first shown, not anymore. You need to run that Task with a Timer or in its own ThreadPool Thread, then repeat after a second or two. You can just `await Task.Delay(1000)` in a loop for that (a loop executed in the ThreadPool Thread, not the UI Thread). – Jimi Aug 23 '21 at 10:59
  • So it needs to go then in the MassPing class? –  Aug 23 '21 at 11:26
  • Nope. All main classes here remain the same (`MassPing`, the `Progress` delegate, the database query, etc.). You need to add a Task that will loop the call to `PingAll()` and add a delay between calls. I.e., what is now `await massPing.PingAll(ipAddresses.ToArray(), progress, 2500);` must be moved to a stand-alone Task and looped (as the most simple method). – Jimi Aug 23 '21 at 11:29
  • Nope, this is a bit more complicated than what I thought. I know what you mean but don't know how to implement it. –  Aug 23 '21 at 12:01
  • Thank you so much, I have been googling and trying to find a solution, but to no avail. I appreciate your help on this and have learned a whole from your regarding this :-) Thanks –  Aug 23 '21 at 12:43
  • Hi, I was just wondering if you had a chance to see what you can do to assist? –  Aug 24 '21 at 05:59
  • When I get close to a Windows machine :) – Jimi Aug 24 '21 at 07:03
  • Thanks :-) I have posted a new question here https://stackoverflow.com/questions/68903057/how-can-i-run-a-task-every-5-seconds-to-run-a-ping-on-ip-addresses?noredirect=1#comment121772551_68903057 just avoid extended discussions. –  Aug 24 '21 at 07:12

0 Answers0