我正在创建一个应该与我的服务器保持联系的客户端应用程序。这种连接不会掉线至关重要,如果确实如此,最终应该重新连接。这非常关键,因此客户不会坐在那里几个小时,想知道为什么没有发生任何事情。
这是我提出的代码:
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)中异步处理,因此如果崩溃,则应该继续运行。
所有这一切的问题是什么?我刚跟客户打电话告诉我,它已经运行了几个小时,什么都没发生。在我的最后,它连接一次几分钟,然后消失,连接仍然没有回来。
我做错了什么?
答案 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