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