1 #Region "Microsoft.VisualBasic::ac78e0e3b6b7dba2c2fa4a4acad57024, Microsoft.VisualBasic.Core\Net\Tcp\TCPExtensions.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 TCPExtensions
35     
36     '         Function: ConnectSocket, GetFirstAvailablePort, (+2 Overloads) Ping, PortIsAvailable, PortIsUsed
37     
38     
39     ' /********************************************************************************/
40
41 #End Region
42
43 Imports System.Net
44 Imports System.Net.NetworkInformation
45 Imports System.Net.Sockets
46 Imports System.Runtime.CompilerServices
47 Imports Microsoft.VisualBasic.Linq.Extensions
48 Imports Microsoft.VisualBasic.Net.Http
49 Imports Microsoft.VisualBasic.Net.Protocols
50
51 Namespace Net.Tcp
52
53     Public Module TCPExtensions
54
55         ''' <summary>
56         ''' -1标识Ping不通
57         ''' </summary>
58         ''' <param name="operationTimeOut">ms</param>
59         ''' <returns></returns>
60         Public Function Ping(ep As System.Net.IPEndPoint, Optional operationTimeOut As Integer = 3 * 1000) As Double
61             Return New TcpRequest(ep).Ping(operationTimeOut)
62         End Function
63
64         ''' <summary>
65         ''' -1 ping failure
66         ''' </summary>
67         ''' <param name="invoke"></param>
68         ''' <param name="timeout"></param>
69         ''' <returns></returns>
70         <Extension>
71         Public Function Ping(invoke As TcpRequest, Optional timeout As Integer = 3 * 1000) As Double
72             Dim sw As Stopwatch = Stopwatch.StartNew
73             Dim request As RequestStream = RequestStream.SystemProtocol(RequestStream.Protocols.Ping, PING_REQUEST)
74             Dim response As RequestStream = invoke.SendMessage(request, timeout:=timeout)
75
76             If HTTP_RFC.RFC_REQUEST_TIMEOUT = response.Protocol Then
77                 Return -1
78             End If
79
80             Return sw.ElapsedMilliseconds
81         End Function
82
83         Public Const PING_REQUEST As String = "PING/TTL-78973"
84
85         ''' <summary>
86         ''' 假若不能成功的建立起连接的话,则会抛出错误
87         ''' </summary>
88         ''' <param name="server"></param>
89         ''' <param name="port"></param>
90         ''' <returns></returns>
91         ''' <remarks></remarks>
92         Public Function ConnectSocket(server As String, port As IntegerAs System.Net.IPEndPoint
93
94             Get host related information.
95             Dim HostEntry As IPHostEntry = Dns.GetHostEntry(server)
96
97             Loop through the AddressList to obtain the supported AddressFamily. This is to avoid
98             ' an exception that occurs when the host host IP Address is not compatible with the address family
99             ' (typical in the IPv6 case).
100             For Each Address As IPAddress In HostEntry.AddressList
101                 Dim endPoint As New System.Net.IPEndPoint(Address, port)
102                 Dim Socket As Socket = New Socket(endPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp)
103
104                 Try
105                     Call Socket.Connect(endPoint)
106                 Catch ex As Exception
107                     Continue For
108                 End Try
109
110                 If Socket.Connected Then
111                     Return endPoint
112                 End If
113             Next
114
115             Throw New Exception(String.Format("The target connection to {0}:{1} can not be made!", server, port))
116         End Function
117
118         Const MAX_PORT As Integer = 65535    '系统tcp/udp端口数最大是65535
119
120         ''' <summary>
121         ''' Get the first available TCP port on this local machine.
122         ''' (获取第一个可用的端口号,请注意,在高并发状态下可能会出现端口被占用的情况,
123         ''' 所以这时候建议将<paramref name="BEGIN_PORT"/>设置为-1,则本函数将会尝试使用随机数来分配可用端口,从而避免一些系统崩溃的情况产生)
124         ''' </summary>
125         ''' <param name="BEGIN_PORT">Check the local port available from this port value.(从这个端口开始检测)</param>
126         ''' <returns></returns>
127         Public Function GetFirstAvailablePort(Optional BEGIN_PORT As Integer = 100) As Integer
128             If BEGIN_PORT <= 0 Then
129                 BEGIN_PORT = Rnd() * (MAX_PORT - 1)  ' 为了避免高并发的时候出现端口占用的情况,在这里使用随机数来解决一些问题
130             End If
131
132             For i As Integer = BEGIN_PORT To MAX_PORT - 1
133                 If PortIsAvailable(port:=i) Then
134                     Return i
135                 End If
136             Next
137
138             Return -1
139         End Function
140
141         ''' <summary>
142         ''' 获取操作系统已用的端口号
143         ''' </summary>
144         ''' <returns></returns>
145         Public Function PortIsUsed() As Integer()
146             '获取本地计算机的网络连接和通信统计数据的信息
147             Dim ipGlobalProperties__1 As IPGlobalProperties = IPGlobalProperties.GetIPGlobalProperties()
148
149             '返回本地计算机上的所有Tcp监听程序
150             Dim ipsTCP As System.Net.IPEndPoint() = ipGlobalProperties__1.GetActiveTcpListeners()
151
152             '返回本地计算机上的所有UDP监听程序
153             Dim ipsUDP As System.Net.IPEndPoint() = ipGlobalProperties__1.GetActiveUdpListeners()
154
155             '返回本地计算机上的Internet协议版本4(IPV4 传输控制协议(TCP)连接的信息。
156             Dim tcpConnInfoArray As TcpConnectionInformation() = ipGlobalProperties__1.GetActiveTcpConnections()
157
158             Dim allPorts As List(Of Integer) = New List(Of Integer)
159             Call allPorts.AddRange((From ep As System.Net.IPEndPoint In ipsTCP Select ep.Port).ToArray)
160             Call allPorts.AddRange((From ep As System.Net.IPEndPoint In ipsUDP Select ep.Port).ToArray)
161             Call allPorts.AddRange((From conn As TcpConnectionInformation In tcpConnInfoArray Select conn.LocalEndPoint.Port).ToArray)
162
163             Return allPorts.ToArray
164         End Function
165
166         ''' <summary>
167         ''' 检查指定端口是否已用
168         ''' </summary>
169         ''' <param name="port"></param>
170         ''' <returns></returns>
171         Public Function PortIsAvailable(port As IntegerAs Boolean
172             Dim portUsed As Integer() = PortIsUsed()
173
174             For Each p As Integer In portUsed
175                 If p = port Then
176                     Return False
177                 End If
178             Next
179
180             Return True
181         End Function
182     End Module
183 End Namespace