Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations strongm on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Multithread ping function

Status
Not open for further replies.

DTJeff

Programmer
Dec 9, 2003
37
GB
Hi all.

I'm currently working on an app that requires the need to ping pc's to check that they are online. The app could pottentially have to check several hundred PC's, and so I've made it a multithreaded application. The problem I'm having is that the code that microsoft suggests for performing a ping is not really thread safe. I've also looked at ready made controls, and they dont seem to work either.

The problem I am getting is this:

Ping 2 IP Addresses, one of which is a PC, the other isnt (no device at all). Assuming that both ping requests are made at the same time (which seems to happen in my app), I get a response from IP address 1 (as I should), but I also get a respone from IP address 2 even though there is no device on this IP address! - Im guessing that the second thread is seeing the response from IP address 1 and not working out that it isnt a response from its own ping request.

I can include the code I'm currently using if needed - but it is a bit long.

Anyone have any ideas or suggestions?

Thanks

Jeff.
 
Hi

I've found a solution to the problem, not ideal but it works perfectly.

I managed to work out how to call another program and read the output from it, and so can use the normal "ping" command.

Code:
    Public Function PingIPAddress(ByVal Destination As String) As Boolean

        Dim PingInfo As New System.Diagnostics.ProcessStartInfo("ping")
        PingInfo.WindowStyle = ProcessWindowStyle.Hidden
        'You can change the attempts at a ping by changing the " -n 1" part to a higher number - e.g. " -n 3"
        'also possible to add other options here such as "-l 64" ( send 64 bytes of data)
        PingInfo.Arguments = Destination & " -n 1"
        PingInfo.CreateNoWindow = True
        PingInfo.UseShellExecute = False
        PingInfo.RedirectStandardOutput = True
        Dim SystemProcess As New System.Diagnostics.Process
        SystemProcess.StartInfo = PingInfo
        SystemProcess.Start()
        SystemProcess.WaitForExit()
        Dim tmpResult As String
        tmpResult = SystemProcess.StandardOutput.ReadToEnd
        If InStr(tmpResult, "Reply from") > 0 Then
            Return True
        Else
            Return False
        End If

    End Function

Theres probably something blaringly obvious here that Im missing that will cause me problems down the line (feel free to let me know if there is :-D ) but it seems to work so far.

Jeff.
 
Jeff,

I found this code the otheday (planet source code)

and it seems to work very well..

I used it in an app I have that launchs 153 processes on 153 pc's (but due to a need for the app to return if a server wasn't avaliable it uses a ping first.

Syntax for using it would be something like
Code:
            Dim oRet As ICMPClass.ICMPReplyStructure
            oRet = p.Ping(pcname, 1000) ' WHEre 1000 is Milliseconds before timeout...

            If oRet.Status = ICMPClass.ICMPStatusEnum.Success Then
Code:
    Imports System.Net
    Imports System.Net.Sockets
    Imports System.Runtime.InteropServices
Public Class ICMPClass
    'Enumerated list of icmp echo reply response codes
    Public Enum ICMPStatusEnum
        Success = 0
        BufferTooSmall = 11001 'Buffer Too Small 
        DestinationNetUnreachable = 11002 'Destination Net Unreachable 
        DestinationHostUnreachable = 11003 'Destination Host Unreachable 
        DestinationProtocolUnreachable = 11004 'Destination Protocol Unreachable 
        DestinationPortUnreachable = 11005 'Destination Port Unreachable 
        NoResource = 11006 'No Resources 
        BadOption = 11007 'Bad Option 
        HardwareError = 11008 'Hardware Error 
        LargePacket = 11009 'Packet Too Big 
        RequestTimedOUT = 11010 'Request Timed Out 
        BadRequest = 11011 'Bad Request 
        BadROUTE = 11012 'Bad Route 
        TtlExpiredInTransit = 11013 'TimeToLive Expired Transit 
        TtlExpiredInReassembly = 11014 'TimeToLive Expired Reassembly 
        Parameter = 11015 'Parameter Problem 
        SourceQuench = 11016 'Source Quench 
        OptionTooBig = 11017 'Option Too Big 
        BadDestination = 11018 'Bad Destination 
        NegotiatingIPSEC = 11032 'Negotiating IPSEC 
        GeneralFailure = 11050 'General Failure 
    End Enum
    'User Friendly ping command that accepts a host as either an ip address 
    'or a resolvable name. 
    'Usage:
    'ex 1: console.WriteLine Ping("192.168.0.1").RoundTripTime
    'ex 2: dim reply as ICMPReplyStructure
    ' reply = Ping("192.168.0.1", 1000,16)
    ' console.WriteLine reply.ReplyFrom.ToString & " replied in " & reply.RoundTripTime & _
    '"ms. status:" & reply.status & ":" & reply.message & ". TTL=" & reply.TTL
    Public Function Ping(ByVal Host As String, Optional ByVal Timeout As Integer = 2000, Optional ByVal TTL As Byte = 32, Optional ByVal DataSize As Long = 32) As ICMPReplyStructure
        Dim IP As IPAddress
        Dim opt As ICMPOptions
        Try
            IP = Dns.GetHostByName(Host).AddressList(0)
        Catch ex As Exception
            Dim r As ICMPReplyStructure
            'create a mock reply 
            r.Message = ex.ToString
            r.ReplyFrom = New IPAddress(0)
            r.Status = ICMPStatusEnum.GeneralFailure
            r.TTL = 255
            'return the error message as a ICMP general error
            Return r
            Exit Function
        End Try
        opt.Timeout = Timeout
        opt.TimeToLive = TTL
        opt.DatSize = DataSize
        Return Ping(IP, opt)
    End Function
    'Code friendly Ping that actually does the work
    Public Function Ping(ByVal IP As IPAddress, ByVal opt As ICMPOptions) As ICMPReplyStructure
        Dim ICMPHandle As IntPtr
        Dim iIP As Int32
        Dim sData As String
        Dim oICMPOptions As New ICMPClass.ICMP_OPTIONS
        Dim ICMPReply As ICMP_ECHO_REPLY
        Dim iReplies As Int32
        ICMPHandle = IcmpCreateFile
        iIP = System.BitConverter.ToInt32(IP.GetAddressBytes, 0)
        sData = "X"
        oICMPOptions.Ttl = opt.TimeToLive
        iReplies = IcmpSendEcho(ICMPHandle, iIP, sData, sData.Length, oICMPOptions, ICMPReply, Marshal.SizeOf(ICMPReply), opt.Timeout)
        Dim reply As ICMPReplyStructure
        reply = FillReplyStructure(ICMPReply)
        Return reply
    End Function
    'return a people friendly message from the status code
    Public Function GetMessage(ByVal status As ICMPStatusEnum) As String
        Select Case status
            Case ICMPStatusEnum.Success
                Return "Success"
            Case ICMPStatusEnum.BufferTooSmall
                Return "Buffer Too Small"
            Case ICMPStatusEnum.DestinationNetUnreachable
                Return "Destination Net Unreachable"
            Case ICMPStatusEnum.DestinationHostUnreachable
                Return " Destination Host Unreachable"
            Case ICMPStatusEnum.DestinationProtocolUnreachable
                Return "Destination Protocol Unreachable"
            Case ICMPStatusEnum.DestinationPortUnreachable
                Return "Destination Port Unreachable"
            Case ICMPStatusEnum.NoResource
                Return "No Resources"
            Case ICMPStatusEnum.BadOption
                Return "Bad Option"
            Case ICMPStatusEnum.HardwareError
                Return "Hardware Error"
            Case ICMPStatusEnum.LargePacket
                Return "Packet Too Big"
            Case ICMPStatusEnum.RequestTimedOUT
                Return "Request Timed Out"
            Case ICMPStatusEnum.BadRequest
                Return "Bad Request"
            Case ICMPStatusEnum.BadROUTE
                Return "Bad Route"
            Case ICMPStatusEnum.TtlExpiredInTransit
                Return "TimeToLive Expired Transit"
            Case ICMPStatusEnum.TtlExpiredInReassembly
                Return "TimeToLive Expired Reassembly"
            Case ICMPStatusEnum.Parameter
                Return "Parameter Problem"
            Case ICMPStatusEnum.SourceQuench
                Return "Source Quench"
            Case ICMPStatusEnum.OptionTooBig
                Return "Option Too Big"
            Case ICMPStatusEnum.BadDestination
                Return "Bad Destination"
            Case ICMPStatusEnum.NegotiatingIPSEC
                Return "Negotiating IPSEC"
            Case ICMPStatusEnum.GeneralFailure
                Return "General Failure"
        End Select
    End Function
    'fill the reply structure which will be passed abck to the user with data
    'from the ICMP_ECHO_REPLY structure.
    Private Function FillReplyStructure(ByVal IER As ICMP_ECHO_REPLY) As ICMPReplyStructure
        Dim irs As ICMPReplyStructure
        Try
            irs.RoundTripTime = IER.RoundTripTime
            irs.Message = GetMessage(IER.Status)
            irs.ReplyFrom = New IPAddress(IER.Address)
            irs.Data = IER.Data
            irs.Status = IER.Status
            irs.TTL = IER.Options.Ttl
        Catch
        End Try
        Return irs
    End Function
    'API functions contained in ICMP.DLL these functions perform the actual pinging
    Private Declare Auto Function IcmpCreateFile Lib "ICMP.DLL" () As IntPtr
    Private Declare Auto Function IcmpSendEcho Lib "ICMP.DLL" _
    (ByVal IcmpHandle As IntPtr, ByVal DestinationAddress As Integer, _
    ByVal RequestData As String, ByVal RequestSize As Integer, _
    ByRef RequestOptions As ICMP_OPTIONS, ByRef ReplyBuffer As ICMP_ECHO_REPLY, _
    ByVal ReplySize As Integer, ByVal Timeout As Integer) As Integer
    <StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Ansi)> _
    Public Structure ICMP_OPTIONS
        Public Ttl As Byte
        Public Tos As Byte
        Public Flags As Byte
        Public OptionsSize As Byte
        Public OptionsData As IntPtr
    End Structure
    <StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Ansi)> _
    Public Structure ICMP_ECHO_REPLY
        Public Address As Integer
        Public Status As ICMPStatusEnum
        Public RoundTripTime As Integer
        Public DataSize As Short
        Public Reserved As Short
        Public DataPtr As IntPtr
        Public Options As ICMP_OPTIONS
        <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=250)> _
        Public Data As String
    End Structure
    Public Structure ICMPReplyStructure
        Public ReplyFrom As IPAddress
        Public RoundTripTime As Integer
        Public Data As String
        Public Status As ICMPStatusEnum
        Public Message As String
        Public TTL As Byte
    End Structure
    Public Structure ICMPOptions
        Public Timeout As Integer
        Public TimeToLive As Byte
        Public DatSize As Long
    End Structure
End Class
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top