vb.net中的tcpClient.State类似物(与vb6.0对比)

时间:2017-03-28 15:08:57

标签: .net vb.net tcp vb6 vb6-migration

我在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"。它永远不会改变它的价值。

1 个答案:

答案 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

现在要获取连接状态,您有三个选项:

  1. 获取TcpClient的状态:

    Dim Status As String = yourClient.GetStatus().ToString()
    
    1. 获取TcpListener的状态:

      Dim Status As String = yourListener.GetStatus().ToString()
      
      1. 获取具有指定IP地址的连接的状态:

        Dim Status As String = New IPEndPoint(IPAddress.Parse("your IP-address here"), yourPortHere).GetStatus().ToString()
        
      2. 重要说明:

        • 如果您需要状态名称(例如ToString()),则需要Established来电,否则您将获得其枚举值,这只是正常情况Integer(例如3)。

        • 获取TcpClientTcpListener的状态只有在他们及其基础Sockets都没有被处理的情况下才有效。如果您希望获得 已断开连接 TcpClient/-Listener的状态,则必须使用选项号。 3 并通过其确切的IP地址和端口获取它。

          • 断开连接的TCP连接实际上也很有趣,因为它们在关闭后仍然存在并且状态有一段时间。断开状态的示例包括CloseWaitTimeWait

        了解详情:

        修改

        要修复在CLOSE_WAITTIME_WAIT状态中延迟的连接问题,您可以将基础Socket设置为逗留0秒,然后将其丢弃。这样做会导致套接字执行所谓的&#34;硬关闭&#34;通过发送RST(重置)数据包而不是FINFIN是告诉套接字连接已关闭并且它应该进入CLOSE-/TIME_WAIT)。此方法强制关闭连接,之后不会将延迟/重新传输的数据包映射到您的应用程序。

        MSDN documentation

        实际上提到了它
          

        如果逗留结构的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()