1 #Region "Microsoft.VisualBasic::ffe7f62e8c3ac70f7bf03ef730c54013, Microsoft.VisualBasic.Core\Net\PingUtility.vb"
2
3     ' Author:
4     
5     '       asuka (amethyst.asuka@gcmodeller.org)
6     '       xie (genetics@smrucc.org)
7     '       xieguigang (xie.guigang@live.com)
8     
9     ' Copyright (c) 2018 GPL3 Licensed
10     
11     
12     ' GNU GENERAL PUBLIC LICENSE (GPL3)
13     
14     
15     ' This program is free software: you can redistribute it and/or modify
16     ' it under the terms of the GNU General Public License as published by
17     ' the Free Software Foundation, either version 3 of the License, or
18     ' (at your option) any later version.
19     
20     ' This program is distributed in the hope that it will be useful,
21     ' but WITHOUT ANY WARRANTY; without even the implied warranty of
22     ' MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23     ' GNU General Public License for more details.
24     
25     ' You should have received a copy of the GNU General Public License
26     ' along with this program. If not, see <http://www.gnu.org/licenses/>.
27
28
29
30     ' /********************************************************************************/
31
32     ' Summaries:
33
34     '     Module PingUtility
35     
36     
37     '         Enum ConnectionState
38     
39     
40     
41     
42     '  
43     
44     '     FunctionInternetGetConnectedState, IsOffline, Ping, PingOnce
45     
46     '     Sub: Print
47     
48     
49     ' /********************************************************************************/
50
51 #End Region
52
53 Imports System.IO
54 Imports System.Net
55 Imports System.Net.NetworkInformation
56 Imports System.Runtime.CompilerServices
57 Imports System.Runtime.InteropServices
58 Imports System.Text
59 Imports Microsoft.VisualBasic.Language
60
61 Namespace Net
62
63     ''' <summary>
64     ''' http://www.codeproject.com/Articles/18635/Ping-exe-replica-in-C
65     ''' 
66     ''' Ping.exe replica in C# 2.0
67     '''
68     ''' Stefan Prodan, 3 May 2007 CPOL
69     ''' Usage example of the System.Net.NetworkInformation.Ping.
70     ''' </summary>
71     ''' <remarks></remarks>
72     Public Module PingUtility
73
74         <Flags> Public Enum ConnectionState As Integer
75             INTERNET_CONNECTION_MODEM = &H1
76             INTERNET_CONNECTION_LAN = &H2
77             INTERNET_CONNECTION_PROXY = &H4
78             INTERNET_RAS_INSTALLED = &H10
79             INTERNET_CONNECTION_OFFLINE = &H20
80             INTERNET_CONNECTION_CONFIGURED = &H40
81         End Enum
82
83         <DllImport("wininet"CharSet:=CharSet.Auto)>
84         Public Function InternetGetConnectedState(ByRef lpdwFlags As ConnectionState, dwReserved As IntegerAs Boolean
85         End Function
86
87         Public Function IsOffline() As Boolean
88             Dim state As ConnectionState = 0
89             InternetGetConnectedState(state, 0)
90             If (CInt(ConnectionState.INTERNET_CONNECTION_OFFLINE) And CInt(state)) <> 0 Then
91                 Return True
92             End If
93
94             Return False
95         End Function
96
97         ''' <summary>
98         ''' 返回与目标远程机器之间的平均通信时间长度
99         ''' </summary>
100         ''' <param name="ip"></param>
101         ''' <param name="out">Default is console.</param>
102         ''' <param name="nTimes">By default is ping 4 times</param>
103         ''' <returns></returns>
104         ''' <remarks></remarks>
105         Public Function Ping(ip As IPAddress,
106                              Optional timeOut As UInteger = 3000,
107                              Optional out As TextWriter = Nothing,
108                              Optional nTimes% = 4,
109                              Optional displayEcho As Boolean = TrueAs Double
110
111             ' set options ttl=128 and no fragmentation
112             Dim options As New PingOptions(128, True)
113             ' create a Ping object
114             Dim pingTools As New Ping()
115             ' 32 empty bytes buffer
116             Dim data As Byte() = New Byte(31) {}
117             Dim received As Integer = 0
118             Dim responseTimes As New List(Of Long)()
119
120             out = out Or App.StdOut
121
122             For i As Integer = 0 To nTimes - 1
123                 With pingTools.PingOnce(ip, timeOut, data, options)
124                     responseTimes += .responseTime
125                     received += .success
126
127                     If displayEcho Then
128                         Call out.WriteLine(.Msg)
129                     End If
130                 End With
131             Next
132
133             ' statistics calculations
134             Dim averageTime As Long = -1
135             Dim minimumTime As Long = 0
136             Dim maximumTime As Long = 0
137
138             For i As Integer = 0 To responseTimes.Count - 1
139                 If i = 0 Then
140                     minimumTime = responseTimes(i)
141                     maximumTime = responseTimes(i)
142                 Else
143                     If responseTimes(i) > maximumTime Then
144                         maximumTime = responseTimes(i)
145                     End If
146                     If responseTimes(i) < minimumTime Then
147                         minimumTime = responseTimes(i)
148                     End If
149                 End If
150
151                 averageTime += responseTimes(i)
152             Next
153
154             If displayEcho Then
155                 Call out.Print(minimumTime, maximumTime, received, averageTime, ip)
156             End If
157
158             If received <= 0 Then
159                 ' Ping不通
160                 Return Double.MaxValue
161             Else
162                 Return averageTime \ received
163             End If
164         End Function
165
166         <Extension>
167         Private Function PingOnce(pingTool As Ping, ip As IPAddress, timeOut As UInt32,
168                                   data As Byte(),
169                                   options As PingOptions) As (success%, responseTime&, Msg$)
170             Dim reply As PingReply = Nothing
171             Dim received%
172
173             Try
174                 reply = pingTool.Send(ip, timeOut, data, options)
175             Catch ex As Exception
176                 Return (0, 10 * 1000, "Error!")
177             End Try
178
179             If reply Is Nothing Then
180                 Return (0, 10 * 1000, "Error!")
181             End If
182
183             Dim responseTime&
184             Dim msg$
185
186             Select Case reply.Status
187                 Case IPStatus.Success
188                     If reply.Options Is Nothing Then
189                         msg = $"Reply from {reply.Address}: bytes={reply.Buffer.Length} time={reply.RoundtripTime}ms"
190                     Else
191                         msg = $"Reply from {reply.Address}: bytes={reply.Buffer.Length} time={reply.RoundtripTime}ms TTL={reply.Options.Ttl}"
192                     End If
193
194                     received = 1
195                     responseTime = reply.RoundtripTime
196                 Case IPStatus.TimedOut
197                     msg = "Request timed out."
198                 Case Else
199                     msg = $"Ping failed {reply.Status.ToString}"
200             End Select
201
202             Return (received, responseTime, msg)
203         End Function
204
205         <Extension>
206         Private Sub Print(out As TextWriter, minimumTime&, maximumTime&, received%, averageTime&, ip As IPAddress)
207             Dim statistics As New StringBuilder()
208             statistics.AppendFormat("Ping statistics for {0}:", ip.ToString())
209             statistics.AppendLine()
210             statistics.AppendFormat("   Packets: Sent = 4, Received = {0}, Lost = {1} <{2}% loss>,", received, 4 - received, Convert.ToInt32(((4 - received) * 100) \ 4))
211             statistics.AppendLine()
212             statistics.Append("Approximate round trip times in milli-seconds:")
213             statistics.AppendLine()
214
215             ' show only if loss is not 100%
216             If averageTime <> -1 Then
217                 statistics.AppendFormat("    Minimum = {0}ms, Maximum = {1}ms, Average = {2}ms", minimumTime, maximumTime, CLng(averageTime \ received))
218             End If
219
220             out.WriteLine()
221             out.WriteLine(statistics.ToString())
222             out.WriteLine()
223         End Sub
224     End Module
225 End Namespace