VB.NET中可靠的网络重新连接循环

时间:2015-01-23 04:40:29

标签: .net vb.net sockets

我正在创建一个应该与我的服务器保持联系的客户端应用程序。这种连接不会掉线至关重要,如果确实如此,最终应该重新连接。这非常关键,因此客户不会坐在那里几个小时,想知道为什么没有发生任何事情。

这是我提出的代码:

Sub Connect()

    //These are actually globals
    Dim client As TcpClient
    Dim lastpacketreceived As DateTime = New DateTime(1, 1, 1)

    While 1
        Try

            If IsNothing(client) Then
                client = New TcpClient(host, port)
                Send("Connect|<credentials>")
                lastpacketreceived = DateTime.Now
                client.GetStream.BeginRead(New Byte() {0}, 0, 0, AddressOf Read, Nothing)
            ElseIf ((DateTime.Now - lastpacketreceived).TotalMinutes > 3 Or client.Connected = False) Then
                Try : client.Client.Close() : Catch : End Try
                Try : client.Close() : Catch : End Try
                client = Nothing
            Else
                //Heartbeat. Receives "pong" from the server that updates the lastpacketreceived timeout counter.
                Send("Ping|") 
            End If

        Catch
        End Try

        Threading.Thread.Sleep(10000)

    End While
End Sub

我希望这个想法非常明确。每10秒循环一次,检查客户端对象是否存在,检查最近3分钟是否有心跳,或者一切正常,只需ping一下即可重置lastpacket接收的超时计数器。

循环使用通用Try / Catch进行屏蔽,接收到的数据在不同的线程(AddressOf Read)中异步处理,因此如果崩溃,则应该继续运行。

所有这一切的问题是什么?我刚跟客户打电话告诉我,它已经运行了几个小时,什么都没发生。在我的最后,它连接一次几分钟,然后消失,连接仍然没有回来。

我做错了什么?

1 个答案:

答案 0 :(得分:1)

有一个更好的模式

  • 循环直到连接。

  • 设置接收循环 - 也测试收到的ZERO字节,这也意味着你断开连接

  • 有独立的发送方式

  • 在单独的循环中定期定时器代码,该循环在一个间隔内重复检查连接。

这是我使用的一些实时代码。您可以根据需要添加其余部分,但这应该可以帮助您入门:

#Region "Variables"
    Public Event Disconneted()

    Const BUFFER_SIZE = 1024 * 64
    Const TIMEOUT = 4000

    Private soc As Socket
    Private ep As EndPoint
    Private loggedin As Boolean
    Private are As New AutoResetEvent(False)
#End Region

Public Sub Connect()
    If IsConnected() = True Then
        Log("Already Connected")
        Exit Sub
    End If

    soc = New Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp) With {.SendBufferSize = BUFFER_SIZE}

    Try
        ep = GetIPEndPointFromHostName("149.154.167.40", 443)

        Dim arg = New SocketAsyncEventArgs With {.RemoteEndPoint = ep}
        AddHandler arg.Completed, AddressOf IO_Handler

        If Not soc.ConnectAsync(arg) Then
            IO_Handler(soc, arg)
        End If

        are.WaitOne(5000)
    Catch ex As Exception
        Log("Connect: " & ex.ToString, ConsoleColor.Red, True)
    End Try

    ReadData()
End Sub

Private Sub SendData(b() As Byte, Optional read As Boolean = False)
    If Not IsConnected() Then
        Log("Connection Closed!", ConsoleColor.DarkRed)
        RaiseEvent Disconneted()
        Exit Sub
    End If

    Dim arg = New SocketAsyncEventArgs With {.RemoteEndPoint = ep}
    AddHandler arg.Completed, AddressOf IO_Handler
    arg.SetBuffer(b, 0, b.Length)

    Try
        If Not soc.SendAsync(arg) Then
            IO_Handler(soc, arg)
        End If

        If read Then
            ReadData()
        End If
    Catch ex As Exception
        Log("SendData: " & ex.ToString, ConsoleColor.Red)
    End Try
End Sub

Private Sub IO_Handler(sender As Object, e As SocketAsyncEventArgs)
    Log($"{e.LastOperation}:{e.SocketError}:{e.BytesTransferred}", ConsoleColor.Cyan)

    Select Case e.SocketError
        Case SocketError.Success
            Select Case e.LastOperation
                Case SocketAsyncOperation.Connect
                    Log("Connected to " & e.ConnectSocket.RemoteEndPoint.ToString, ConsoleColor.Green)
                    are.Set()
                Case SocketAsyncOperation.Disconnect, SocketAsyncOperation.Connect
                    RaiseEvent Disconneted()
                Case SocketAsyncOperation.Receive
                    HandleData(e)
            End Select
        Case SocketError.ConnectionAborted
            RaiseEvent Disconneted()
    End Select
End Sub

Private Function IsConnected() As Boolean
    Dim ret = False

    Try
        If soc IsNot Nothing Then
            ret = Not (soc.Poll(1, SelectMode.SelectRead) And soc.Available = 0)

            If ret = False Then
                loggedin = False
            End If
        End If
    Catch ex As Exception
        loggedin = False
    End Try

    Return ret
End Function

Private Function GetIPEndPointFromHostName(hostName As String, port As Integer) As IPEndPoint
    Dim addresses = System.Net.Dns.GetHostAddresses(hostName)
    If addresses.Length = 0 Then
        Log("Unable to retrieve address from specified host name:  " & hostName, ConsoleColor.Red)
        Return Nothing
    End If
    Return New IPEndPoint(addresses(0), port)
End Function