Reputation: 1157
I have an application that currently runs a ping against about 60 different gateways to monitor internet uptime for my clients as I want to know if their internet drops out before they do. So currently my application runs through a loop starting at the first one (runs 4 pings) waits 2 seconds and then moves on to the next gateway address. I have then implemented some code to retry a number of times if the ping results as a failure as I want to be 100% sure that their connection is down before sending an alert.
The problem with this method is that it takes around 1 or 2 minutes (or sometimes longer) before the same gateway is scanned again, meaning that if the connection was to drop out straight after a ping, I wouldn't know for nearly 2 minutes. I know this sounds miniscule but I would much rather instant alerting to my team so they can act on this immediately.
Therefore, my question is: Would it be better (and what would be the impact) of running 60 separate pings (on different threads maybe) instead of cycling through each one. This way I could run a continuous ping on each gateway at the same time. However, I am worried about performance impact on my application and if it will create too much load on the system.
Any advice would be appreciated. Thanks
EDIT
I have created the following code which works but seems to impact a single processor core heavily and whilst this method works without error, it seems to deem the GUI as in-responsive soon after:
Public Sub PingHost()
Try
GatewayScanning = True
For i As Integer = 0 To Gateways.Count - 1
Dim t As New Threading.Thread(AddressOf CheckHostOnline)
t.IsBackground = True
t.Start(Gateways(i))
Next
Catch ex As Exception
ErrorTrap(ex, "OfflineClientHandler: PingHost()")
End Try
End Sub
Public Sub CheckHostOnline(ByVal gw As Object)
Try
Dim _gateway As Gateway_Object = DirectCast(gw, Gateway_Object)
Dim pingSender As New Ping()
Dim options As New PingOptions()
'Dim averageTime As Integer
Dim OfflinePingCount As Integer = 0
' Use the default Ttl value which is 128,
' but change the fragmentation behavior.
options.DontFragment = False
options.Ttl = 128
' Create a buffer of 32 bytes of data to be transmitted.
Dim data As String = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
Dim buffer() As Byte = Encoding.ASCII.GetBytes(data)
Dim timeout As Integer = 3000
Do While Not GatewayScanning = False
Dim reply As PingReply = pingSender.Send(_gateway.Gateway, timeout, buffer, options)
If reply.Status = IPStatus.Success Then
Dim resultTime As Integer = GetMs(CInt(reply.RoundtripTime))
_gateway.Status = "ONLINE"
_gateway.Result = resultTime
Else
OfflinePingCount += 1
If OfflinePingCount < (My.Settings.OfflinePingCycleNumber * 4) Then
_gateway.Status = "TIMEOUT"
_gateway.Result = -1
Else
_gateway.Status = "OFFLINE"
_gateway.Result = -1
End If
End If
SyncLock class_OfflineGateways
class_OfflineGateways.UpdateListView(_gateway)
End SyncLock
System.Threading.Thread.Sleep(2000)
Loop
pingSender.Dispose()
Catch ex As Exception
ErrorTrap(ex, "OfflineClientHandler: CheckHostOnline()")
End Try
End Sub
Upvotes: 0
Views: 2828
Reputation: 15813
One way to do this is to cycle through the 60 IPs on different threads, and require a five-second (or some amount of time) delay before beginning the cycle again.
Another way is to us asynchronous pings instead of separate threads.
Last time I did this, I ended up using a single thread with 10 ms sleep delay between pings. There were too many ping failures whenever I bunched them together, either with threads or asynch pings. I never did figure out whether the problem was on the server end or on the destination network.
Here's a class I used to ping a list of IP addresses. It (and a bunch of other stuff) ran as a service on an ISP server. (I notice I still have the backgroundworker declared, although it's no longer used.)
Imports System.Net
Imports System.Threading
Imports System.Collections.Generic
Class pingGroup
' used to ping each IP in Targets
Public Targets As New List(Of IPAddress)
Public sectorID As Integer
Public nErrors As Integer = 0
Public Timeout As Integer = pingTimeout
Public PingLog As New List(Of String)
Public PingAvg As Integer = -2 ' -2 = uninit, -1 = error, else average ms excluding the slowest
Public PingTime As DateTime
Public pingCount As Integer = 0
Public pingStarts As Integer = 0
Dim msTotal As Integer = 0
Dim WithEvents bkgPing As System.ComponentModel.BackgroundWorker
Public Sub New(ByVal groupSectorID As Integer)
sectorID = groupSectorID
End Sub
Public Sub Ping()
' run a pingtest once, adding the result incrementally
Dim ip As IPAddress
Dim reply As NetworkInformation.PingReply
Dim ms As Integer
PingTime = Now
If PingLog.Count <= 0 Then PingLog.Add(Format(Now, "G") & " Ping Test")
For Each ip In Targets
Using pPing As New NetworkInformation.Ping
Try
pingStarts = pingStarts + 1
reply = pPing.Send(ip, Timeout)
If reply.Status = NetworkInformation.IPStatus.Success Then
ms = reply.RoundtripTime
pingCount = pingCount + 1
msTotal = msTotal + ms
If pingCount > 0 Then PingAvg = msTotal / pingCount
PingLog.Add(reply.Address.ToString & " " & ms)
Else
nErrors = nErrors + 1
PingLog.Add(Format(Now, "G") & " ---Ping Error: " & ip.ToString & " " & reply.Status.ToString)
End If
Catch ex As Exception
nErrors = nErrors + 1
PingLog.Add(Format(Now, "G") & " ===Ping Error: " & ip.ToString & " " & ex.Message)
End Try
End Using
Thread.Sleep(10)
Next ip
End Sub
End Class
Upvotes: 1