我在VB6.0中使用了Winsock对象tcpClient的下一个代码:
Dim SConst(10) As String
Dim st As Integer
SConst(0) = "Closed"
SConst(1) = "Open"
SConst(2) = "Listening"
SConst(3) = "ConnectionPending"
SConst(4) = "ResolvingHost"
SConst(5) = "HostResolved"
SConst(6) = "Connecting"
SConst(7) = "Connected"
SConst(8) = "Closing"
SConst(9) = "Error"
st = tcpClient.state
TextBox1.Text = SConst(st)
现在我正在使用vb.net并希望做同样的事情。
但是现在.state
个对象没有TcpClient
方法!
只有cpClient.Connected
但它会返回Boolean
所以只有是或否。我怎么能这样做VB6.0?
使用Visual Vinsent's answer我做了这个:
Public Class Form1
Dim status1 As String
Dim status2 As String
Private Sub Btn_Connect5001_Click(sender As Object, e As EventArgs)_
Handles Btn_Connect5001.Click
' Create TcpClient and Connect to
tcpclnt2 = New TcpClient
Try
tcpclnt2.Connect("192.168.1.177", 5001)
Catch
End Try
End Sub
Private Sub Btn_Disconnect5001_Click(sender As Object, e As EventArgs)_
Handles Btn_Disconnect5001.Click
' Close TcpClient
tcpclnt2.Close()
End Sub
Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick
' Check status every 300ms
status2= New IPEndPoint(IPAddress.Parse("192.168.1.177"),5001).GetStatus().ToString()
TextBox1.Text = Dns.GetHostName + Environment.NewLine +
"port 1 " + status2 + Environment.NewLine
End Sub
End Class
问题是:开始时status2
是"未知",如果我第一次连接status2
是"已建立&#34 34 ;.如果我断开它就成了" TimeWait"。但是,如果我再连接一次,它会停留在#34; TimeWait"。它永远不会改变它的价值。
答案 0 :(得分:2)
TcpClient
及其基础Socket
似乎都没有这样的实现,因此我编写了三种扩展方法,可以为您提供。
他们做的是他们使用IPGlobalProperties
class及其GetActiveTcpConnections()
method迭代计算机上的每个活动TCP连接,然后它们与TcpClient
本地的连接匹配和远程IP地址。
<强> Extensions.vb 强>
Imports System.Runtime.CompilerServices
Imports System.Reflection
Imports System.Net
Imports System.Net.Sockets
Imports System.Net.NetworkInformation
Public Module Extensions
''' <summary>
''' Dynamically gets an object's property by name.
''' </summary>
''' <param name="Obj">The object which's property to get.</param>
''' <param name="PropertyName">The name of the property to get.</param>
<Extension()> _
Public Function GetProperty(ByVal Obj As Object, ByVal PropertyName As String) As Object
Return Obj.GetType().InvokeMember(PropertyName, _
BindingFlags.GetProperty _
Or BindingFlags.IgnoreCase _
Or BindingFlags.Public _
Or BindingFlags.NonPublic _
Or BindingFlags.Instance _
Or BindingFlags.Static, _
Nothing, Obj, Nothing)
End Function
''' <summary>
''' Gets the status of a TCP connection.
''' </summary>
''' <param name="Client">The TcpClient which's status to get.</param>
''' <remarks></remarks>
<Extension()> _
Public Function GetStatus(ByVal Client As TcpClient) As TcpState
If Client Is Nothing OrElse Client.Client Is Nothing Then Return TcpState.Unknown
For Each TcpConnection As TcpConnectionInformation In IPGlobalProperties.GetIPGlobalProperties().GetActiveTcpConnections()
If TcpConnection.LocalEndPoint.Equals(Client.Client.LocalEndPoint) AndAlso _
TcpConnection.RemoteEndPoint.Equals(Client.Client.RemoteEndPoint) Then
Return TcpConnection.State
End If
Next
Return TcpState.Unknown
End Function
''' <summary>
''' Gets the status of a TCP connection.
''' </summary>
''' <param name="EndPoint">The IPEndPoint (IP-address) of the TCP connection which's status to get.</param>
''' <remarks></remarks>
<Extension()> _
Public Function GetStatus(ByVal EndPoint As IPEndPoint) As TcpState
If EndPoint Is Nothing Then Return TcpState.Unknown
For Each TcpConnection As TcpConnectionInformation In IPGlobalProperties.GetIPGlobalProperties().GetActiveTcpConnections()
If TcpConnection.LocalEndPoint.Equals(EndPoint) OrElse _
TcpConnection.RemoteEndPoint.Equals(EndPoint) Then
Return TcpConnection.State
End If
Next
Return TcpState.Unknown
End Function
''' <summary>
''' Gets the status of a TCP listener.
''' </summary>
''' <param name="Listener">The TcpListener which's status to get.</param>
''' <remarks></remarks>
<Extension()> _
Public Function GetStatus(ByVal Listener As TcpListener) As TcpState
If Listener Is Nothing OrElse Listener.Server Is Nothing Then Return TcpState.Unknown
'Per the source code, active listeners will always be in the "Listen" state:
'https://referencesource.microsoft.com/#System/net/System/Net/NetworkInformation/SystemIPGlobalProperties.cs,51fa569e558be704
If Listener.GetProperty("Active") = True Then Return TcpState.Listen
Return DirectCast(Listener.LocalEndpoint, IPEndPoint).GetStatus() 'The listener is not in an active state.
End Function
End Module
现在要获取连接状态,您有三个选项:
获取TcpClient
的状态:
Dim Status As String = yourClient.GetStatus().ToString()
获取TcpListener
的状态:
Dim Status As String = yourListener.GetStatus().ToString()
获取具有指定IP地址的连接的状态:
Dim Status As String = New IPEndPoint(IPAddress.Parse("your IP-address here"), yourPortHere).GetStatus().ToString()
重要说明:
如果您需要状态名称(例如ToString()
),则需要Established
来电,否则您将获得其枚举值,这只是正常情况Integer
(例如3
)。
获取TcpClient
或TcpListener
的状态只有在他们及其基础Sockets
都没有被处理的情况下才有效。如果您希望获得 已断开连接 TcpClient/-Listener
的状态,则必须使用选项号。 3 并通过其确切的IP地址和端口获取它。
CloseWait
或TimeWait
。了解详情:
TCP Protocol Operation - Wikipedia(不同TCP连接状态的列表)
修改强>
要修复在CLOSE_WAIT
或TIME_WAIT
状态中延迟的连接问题,您可以将基础Socket
设置为逗留0秒,然后将其丢弃。这样做会导致套接字执行所谓的&#34;硬关闭&#34;通过发送RST
(重置)数据包而不是FIN
(FIN
是告诉套接字连接已关闭并且它应该进入CLOSE-/TIME_WAIT
)。此方法强制关闭连接,之后不会将延迟/重新传输的数据包映射到您的应用程序。
如果逗留结构的
l_onoff
成员非零并且l_linger
成员为零,则即使尚未发送或确认排队数据,也不会阻止closesocket
。这被称为硬或中断关闭,因为套接字的虚拟电路立即被重置,并且任何未发送的数据都将丢失。在Windows上,电路远程端的任何recv
呼叫都将失败并显示WSAECONNRESET
。
这可以通过简单的扩展方法完成(将其放在Extensions
模块中):
''' <summary>
''' Forces the specified TcpClient to close without sending FIN to the other endpoint. This will stop the connection from going into a TIME_WAIT, CLOSE_WAIT or FIN_* state.
''' </summary>
''' <param name="Client">The TcpClient to close.</param>
''' <remarks></remarks>
<Extension()> _
Public Sub ForceClose(ByVal Client As TcpClient)
Client.Client.LingerState = New LingerOption(True, 0) 'Set the socket to linger, but for 0 seconds (causes the current connection to send an RST-packet and terminate).
Client.Client.Dispose() 'Dispose the underlying socket instead of a graceful shutdown.
Client.Close() 'Close the TcpClient.
End Sub
然后就这样称呼它:
yourClient.ForceClose()