Ok so for a while now ive had a program that pings about 15 computers on my network, but the way i have it is pretty messy, id like to somehow make the code a bit cleaner.
so what i have is something like this
vb Code:
Private Sub Ping()
If My.Settings.server1ip <> String.Empty Then
Dim MyPing As New System.Net.NetworkInformation.Ping
Dim MyPingResult As System.Net.NetworkInformation.PingReply = MyPing.Send(My.Settings.server1ip)
If MyPingResult.Status = Net.NetworkInformation.IPStatus.Success Then
so what i have is i copy that code 10 times and rename each sub to ping1 ping2 ping 3 etc. then i have a button with code like this
vb Code:
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Ping()
Ping2()
Ping3()
Ping4()
Ping5()
Ping6()
Ping7()
End Sub
so that runs all my pings... now as you can see its a mess, and im sure its not the best way to go about it. so is there a way i can mold all that into 1 sub? i dont want to ping a range of computers, i want to ping a specific 15-20 ip's.
One way you could do this would be to create a separate thread for each ping, that way you are not waiting on the response of your first ping, before the second one happens.
Here is some code that I got from a Microsoft example on their Coding For Fun website a while back, in your button push put this:
Code:
'
' The NetScan will perform the pings on separate threads
'
Dim ns As NetScan = New NetScan()
'
' Event handler for when each ping completes.
'
AddHandler ns.PingComplete, AddressOf PingComplete
'
' Event handler for when all pings have completed.
'
AddHandler ns.NetScanComplete, AddressOf NetScanComplete
'
' Disable the "Scan" button while the pings are running, and start the pings.
'
scanButton.Enabled = False
ns.Start(New PingRange(startIP, endIP))
Where the worker methods are declared as:
Code:
Private Sub PingComplete(ByVal s As Object, ByVal ev As NetScanCompletedEventArgs)
If ev.Reply.Status = IPStatus.Success Then
Dim li As ListViewItem = New ListViewItem(New String() {ev.Reply.Address.ToString(), ev.Reply.RoundtripTime.ToString(CultureInfo.InvariantCulture) + " ms"})
resultsListView.Items.Add(li)
End If
End Sub
Private Sub NetScanComplete(ByVal s As Object, ByVal ev As EventArgs)
scanButton.Enabled = True
End Sub
And then, in another class, have the following:
Code:
Imports System.Collections.Generic
Imports System.Text
Imports System.Windows.Forms
Imports System.Net
Imports System.Net.NetworkInformation
Imports System.Threading
Public Class NetScan
Inherits Control
'
' Fired when each ping completes
'
Public Event PingComplete As EventHandler(Of NetScanCompletedEventArgs)
'
' Fired when all pings complete
'
Public Event NetScanComplete As EventHandler(Of EventArgs)
'
' Limits the number of pings happening simultaniously
'
Const THREAD_COUNT As Integer = 200
Private pingBlock As Semaphore = New Semaphore(0, THREAD_COUNT)
''' <summary>
''' Constructor
''' </summary>
Public Sub New()
'
' Needed before Control.Invoke will work.
'
Dim i As IntPtr = Me.Handle
'
' All items in the semaphore start out locked. This releases them all.
'
pingBlock.Release(THREAD_COUNT)
End Sub
''' <summary>
''' Starts ping operations on a background thread.
''' </summary>
''' <param name="pr">Contains the starting and ending IP address for the pings.</param>
Public Sub Start(ByVal pr As PingRange)
Dim t As Thread = New Thread(New ParameterizedThreadStart(AddressOf pingWorker_DoWork))
t.Start(New PingRange(pr.StartRange, pr.EndRange))
End Sub
''' <summary>
''' Loops through the IP address and does the pings.
''' </summary>
''' <remarks></remarks>
''' <param name="o">Start and end IP addresses to ping.</param>
Private Sub pingWorker_DoWork(ByVal o As Object)
Dim pingRange As PingRange = CType(o, PingRange)
'
' Get the starting and ending address as a byte array to make it easier to
' loop through.
'
Dim startRange As Byte() = pingRange.StartRange.GetAddressBytes()
Dim endRange As Byte() = pingRange.EndRange.GetAddressBytes()
'
' Each thread that's spawned will be put in this list so that it's easy to
' know when they've all completed.
'
Dim threads As LinkedList(Of Thread) = New LinkedList(Of Thread)()
'
' Loop through each octet in the IP address, and ping on a background thread.
'
For o0 As Byte = startRange(0) To endRange(0)
For o1 As Byte = startRange(1) To endRange(1)
For o2 As Byte = startRange(2) To endRange(2)
For o3 As Byte = startRange(3) To endRange(3)
pingBlock.WaitOne()
Dim t As Thread = New Thread(New ParameterizedThreadStart(AddressOf DoPing))
t.Start(New IPAddress(New Byte() {o0, o1, o2, o3}))
threads.AddTail(t)
Next o3
Next o2
Next o1
Next o0
'
' Wait until all the pings are done.
'
For Each ln As Thread In threads
ln.Join()
Next
'
' Raise an event saying the pings are done on the main UI thread.
'
Try
Me.Invoke(New RaiseNetScanCompleteHandler(AddressOf RaiseNetScanComplete))
Catch ex As InvalidOperationException
' Can happen if the application is closed while pings are going on in
' the background. Safe to ignore.
End Try
End Sub
Private Delegate Sub RaiseNetScanCompleteHandler()
''' <summary>
''' Fire an event to the client on the same thread that they invoked this
''' object on so that the UI can be safely updated.
''' </summary>
Private Sub RaiseNetScanComplete()
RaiseEvent NetScanComplete(Me, New EventArgs())
End Sub
''' <summary>
''' Perform the actual ping, and release the semaphore so that another thread
''' can go.
''' </summary>
''' <param name="o">IP address to ping</param>
Private Sub DoPing(ByVal o As Object)
Dim ip As IPAddress = CType(o, IPAddress)
Dim newPing As Ping = New Ping()
Dim pr As PingReply = newPing.Send(ip)
pingBlock.Release()
Try
Me.Invoke(New PingResults(AddressOf Results), New Object() {pr})
Catch ex As InvalidOperationException
' Can happen if the application is closed while pings are going on in
' the background. Safe to ignore.
End Try
End Sub
Protected Delegate Sub PingResults(ByVal pr As PingReply)
''' <summary>
''' Fire an event when each ping completes so that the client can show
''' progress
''' </summary>
''' <param name="pr">Ping Results</param>
Sub Results(ByVal pr As PingReply)
Dim e As NetScanCompletedEventArgs = New NetScanCompletedEventArgs()
e.Reply = pr
RaiseEvent PingComplete(Me, e)
End Sub
End Class
Also:
Code:
Imports System
Imports System.Collections.Generic
Imports System.Text
Imports System.Net.NetworkInformation
Public Class NetScanCompletedEventArgs
Inherits EventArgs
Private _reply As PingReply
Public Property Reply() As PingReply
Get
Return _reply
End Get
Set(ByVal value As PingReply)
_reply = value
End Set
End Property
End Class
And one more:
Code:
Imports System.Collections.Generic
Imports System.Text
Imports System.Net
Public Class PingRange
Private _startRange As IPAddress
Public Property StartRange() As IPAddress
Get
Return _startRange
End Get
Set(ByVal value As IPAddress)
_startRange = value
End Set
End Property
Private _endRange As IPAddress
Public Property EndRange() As IPAddress
get
Return _endRange
End Get
Set(ByVal value As IPAddress)
_endRange = value
End Set
End Property
Public Sub New(ByVal startRange As IPAddress, ByVal endRange As IPAddress)
_startRange = startRange
_endRange = endRange
End Sub
Public Sub New(ByVal startRange As Long, ByVal endRange As Long)
_startRange = New IPAddress(startRange)
_endRange = New IPAddress(endRange)
End Sub
End Class
I used the above in an application that I created and was able to get near real time representations of the current status of 10 computers which were connected over our business VPN.
That NetScan class looks pretty good. The OP can modify it slightly to ping a collection of IP addresses instead of an IP range, since most servers in an intranet environment do not have their IP addesses in sequence.
Let us have faith that right makes might, and in that faith, let us, to the end, dare to do our duty as we understand it. - Abraham Lincoln -
That NetScan class looks pretty good. The OP can modify it slightly to ping a collection of IP addresses instead of an IP range, since most servers in an intranet environment do not have their IP addesses in sequence.
Hey,
That is basically exactly what I did to modify it as well. I passed in a collection of IP Addresses and looped through each one and pinged that IP address.
The example that I took that class from was designed to find all the computers on your network. i.e. you give a subnet and it will go and find all the computers on your network.
I don't have the code I modified to hand, but from what I remember, it wasn't that difficult.
Sorry, the example that I pasted from doesn't use a subnet mask, it simply pings everything between the start and end IP Address. Lets say your IP Address was 192.168.1.12, and you wanted to find every computer on your network and you had a subnet mask of 255.255.225.0, then you would put 192.168.1.0 in the start and 192.168.1.255 in the end. It doesn't take a mask into consideration. I guess it could be modified to take that into consideration, but that is not functionality that I used, or that has been asked for.
IMHO - it is a shame that .Address is an ObsoleteAttribute("This property has been deprecated...
Code:
Dim testIP As IPAddress = IPAddress.Parse("192.168.1.1")
Dim testMask As IPAddress = IPAddress.Parse("255.255.255.255")
Dim testadd1 As IPAddress = IPAddress.Parse("0.0.0.1")
testMask.Address = testIP.Address And testMask.Address
Debug.WriteLine(testMask.ToString)
testIP.Address = testMask.Address + testadd1.Address
Debug.WriteLine(testIP.ToString)
I wrote an address scanner that was pretty short and took care of mask's using the .Address
Last edited by dbasnett; Oct 16th, 2008 at 04:07 PM.
Don't know if anyone's still checking this thread...
I've been writing a remote control app for Cisco phones recently and realised that being able to ping a network to find valid ips in use would be very handy...
this code looks perfect (if a little over my head)..
I'm having a little bit of difficulty with a very basic issue...
at the line:
ns.Start(New PingRange(startIP, endIP))
i get the error:
Conversion from string "10.50.200.0" to type 'Long' is not valid.
i suspect this is caused by how i've declared my startIP and endIP variables...
i declared them as string... what should they be?
if i declare them as anything else i get an error trying to read in the values from the text boxes into the variables...
Sorry to ask such basic stuff but it would be very very helpful if someone could advise!
Woudlent this be the easiest so he can keep his code:
Code:
Private Sub Ping(ByVal ip As String)
If My.Settings.server1ip <> String.Empty Then
Dim MyPing As New System.Net.NetworkInformation.Ping
Dim MyPingResult As System.Net.NetworkInformation.PingReply = MyPing.Send(ip)
If MyPingResult.Status = Net.NetworkInformation.IPStatus.Success Then
Me.txtServer1Status.ForeColor = Color.Green
Me.txtServer1Status.Text = ("Online")
Me.txtServer1Reply.Text = (MyPingResult.RoundtripTime.ToString & " ms")
If MyPingResult.RoundtripTime.ToString > 200 Then
Me.txtServer1Reply.ForeColor = Color.Red
Else
If MyPingResult.RoundtripTime.ToString > 100 Then
Me.txtServer1Status.ForeColor = Color.Orange
End If
End If
Else
Me.txtServer1Status.ForeColor = Color.Red
Me.txtServer1Status.Text = ("Failed")
End If
Else
Me.txtServer1Status.Text = ("No IP Entered")
End If
End Sub
That is a simple solution in the sense that you have to wait for one ping to finish before the next one happens. Given that each ping, by default has a timeout of 4 seconds, the code you have shown could potentially take 8 seconds to complete.
If you are trying to ping all the IP Addresses on your network one after the other, you can see that this potentially builds up to a long period of time.
The benefit of the code that I posted is that it starts each ping off in a separate thread, so that each Ping executes at the same time, thus you can do all the pings in the same time as it takes to do one.
So my question would be, have you declared the Results Sub that is used as the delegate method, this should be declared as follows:
Code:
''' <summary>
''' Fire an event when each ping completes so that the client can show
''' progress
''' </summary>
''' <param name="pr">Ping Results</param>
Sub Results(ByVal pr As PingReply)
Dim e As NetScanCompletedEventArgs = New NetScanCompletedEventArgs()
e.Reply = pr
RaiseEvent PingComplete(Me, e)
End Sub
i just need one more bit of help if you would be so kind...
i need to send an extra HTTP request to each IP while it pings, i.e. ping, and if the response is successful send an http request
This is the code i need to add:
Code:
objSvrHTTP.open("GET", "http://" + IP + "/DeviceInformation", False)
objSvrHTTP.send()
DeviceInformation = objSvrHTTP.responseText
If InStr(DeviceInformation, "Cisco Communicator ") > 0 Then
PhoneType = "IP Communicator"
ElseIf InStr(DeviceInformation, "7970") > 0 Then
PhoneType = "7970"
ElseIf InStr(DeviceInformation, "7960") > 0 Then
PhoneType = "7960"
End If
where should i put that in my code? i've also got a slight problem in that i would need to reconvert the ip address to a string so i can send it in the http request right?
You could either ping everyone on the subnet, if it works, then record the IpAddress in a list, then start looping through this list using the same technique as above (that is if you want them to execute on separate threads) and perform the HttpRequest.
If you look at the members of the IpAddress Class:
I've put my code in with the ping requests and stepping through it it seems to be doing the right thing!...
my only issue now is getting the variable "PhoneType" back to the list box on the form...
i was originally thinking i needed to pass it from the "DoPing" sub to the "PingResults" sub using the line:
Code:
Me.Invoke(New PingResults(AddressOf Results), New Object() {pr,PhoneType})
then pass it from "PingResults" to "PingComplete" which is a sub on the form using:
Code:
RaiseEvent PingComplete(Me, e, PhoneType )
. but i get an error when i try this.
Any ideas of how to pass this variable back to the original form? then i think i am done
sorry, i'm sure this should be very simple, i'm trying my utmost to understand the code you sent and i'm pretty much there but it's just this bit that's baffling me.
VB Code:
''' <summary>
''' Perform the actual ping, and release the semaphore so that another thread
DoPing is the worker method for the actual Ping, so while in that method, you don't actually know if the ping was successful, so in my opinion, this would be the wrong place to put it. Rather, you would want to start the HttpWebRequest at the point that you know the Ping has come back successfully, i.e.
Code:
Private Sub PingComplete(ByVal s As Object, ByVal ev As NetScanCompletedEventArgs)
If ev.Reply.Status = IPStatus.Success Then
Dim li As ListViewItem = New ListViewItem(New String() {ev.Reply.Address.ToString(), ev.Reply.RoundtripTime.ToString(CultureInfo.InvariantCulture) + " ms"})
resultsListView.Items.Add(li)
End If
End Sub
Once you know that the Ping came back, you should then fire off the HttpWebRequest.
Also, a small point, it looks like you are using some older object types, for which there are newer versions in the framework, i.e. for the FileSystem you might want to look at the System.IO namespace and for the actual Request, look at the HttpWebRequest class.
I would have to see the code that you have implemented in order to answer that fully.
Basically, it depends on what exactly you have done. The code that I have given you will fire off each ping on a separate thread. Assuming you are doing some additional logic if a ping comes back successfully then you will need to handle the creation of new threads at that point.
Imports System.Net.NetworkInformation
Public Class Form1
Dim listIP As List(Of String)
Dim status As List(Of String)
Dim count As Integer
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim anIP As String = "192.168.1.0"
Dim aMask As String = "255.255.255.0"
Dim aPing As Ping
'ipRange can be found here:
'http://www.vbforums.com/showpost.php?p=3377404&postcount=5
listIP = ipRange(anIP, aMask)
status = New List(Of String)
status.AddRange(listIP.ToArray)
For x As Integer = 1 To listIP.Count - 1
aPing = New Ping
AddHandler aPing.PingCompleted, AddressOf pchdlr
status(x) = ""
System.Threading.Interlocked.Increment(count)
aPing.SendAsync(listIP(x), 100, x)
Next
End Sub
Private Sub pchdlr(ByVal sender As Object, ByVal args As PingCompletedEventArgs)
status(CInt(args.UserState)) = args.Reply.Status.ToString
System.Threading.Interlocked.Decrement(count)
End Sub
End Class
pcList is an array with the name of all the pcs on the network.
lbAPIComputers is a ListBox with the names of the pc's the i've pinged and the result is a succes and the lbNonAcsPC is another ListBox with the names of the pc's i've pinged but the result isn't success...
The problem is that after it pings the first PC it stops (?) and automatically adds the other names to lbNonAcsPC (without even pinging them, I asume).
I've read the post #32, but I don't quite get it. Is it pinging on a different thread? How can I modify it to fit my purposes?
Thanks in advance!!
"In our profession, precision and perfection are not a dispensable luxury, but a simple necessity."
Niklaus E. Wirth
Rate any post that helped you, it's a good way of saying thanks
Please specify your Visual Studio Version!
Have you had a look at the sample that I posted in post #21. This will do exactly what you want. It may take some "tinkering" to get it to work with the array that you are using, but it will definitely do it.
In that sample, each ping is executed on a separate thread.
I am building a similar application, but am not pinging ranges of ip addresses, but five different ip addresses. how do i go about editing it the code.
One way of doing this would be to modify the Start method of the NetScan class to accept a List of IPAddress, rather than an IPRange. Construct the List, and add the IP Addresses that you want into it, then in the pingWorker_DoWork method you can loop through the List and ping all the ones that you want.
I am building a similar application, but am not pinging ranges of ip addresses, but five different ip addresses. how do i go about editing it the code.
I have a codebank example on doing async ping requests to multiple IPs and listening for the results. You can find that here.