Imports System.ComponentModel
Imports System.Net
Imports System.Net.Sockets
Imports System.Text
Imports System.Threading
Public Class TcpClientHelper
Inherits Component
Private m_csTcpClient As TcpClient
Public m_csNetworkStream As NetworkStream
Public m_strIP As String = "127.0.0.1"
Public m_intPort As UInt16 = 8080
Private readBytes() As Byte
Private tcpClientLock As New Object()
Public Property m_csIPEndPoint As IPEndPoint = Nothing '服务器IP和端口
Public Property ISBreaklineReconnection As Boolean = False
Public Event RecvMsgEvent(strMSG As String)
Public Event DisconnectEvent(strMSG As String)
Public Event LogMsg(csException As Exception)
Private m_bolISActive As Boolean = False
Dim csBackgroundWorker As New System.ComponentModel.BackgroundWorker
Public Sub New()
AddHandler csBackgroundWorker.DoWork, AddressOf WorkerDoWork
End Sub
Public ReadOnly Property ISActive() As Boolean
Get
Return m_bolISActive
End Get
End Property
''' <summary>
''' 一直连接直到成功
''' </summary>
Public Sub ReConnect()
If csBackgroundWorker.IsBusy = False AndAlso m_bolISActive = False Then
csBackgroundWorker.RunWorkerAsync()
End If
End Sub
Private Sub WorkerDoWork(sender As Object, e As DoWorkEventArgs)
Try
Dim isReconnect As Boolean = True
Dim tryReconnectTimes As Integer = 0
Dim m_csWaitHandle As New ManualResetEvent(False)
While isReconnect AndAlso csBackgroundWorker.CancellationPending = False
Try
If Connect() = False Then
isReconnect = True
Else
isReconnect = False
End If
Catch ex As Exception
RaiseEvent LogMsg(ex)
End Try
m_csWaitHandle.WaitOne(1000)
End While
Catch ex As Exception
RaiseEvent LogMsg(ex)
End Try
End Sub
''' <summary>
''' 一次连接
''' </summary>
''' <returns></returns>
Public Function Connect() As Boolean
If m_csIPEndPoint Is Nothing Then
Throw New Exception("未设置IP地址和端口号!")
Return False
End If
Try
m_csTcpClient = New TcpClient(AddressFamily.InterNetwork)
m_csTcpClient.ReceiveTimeout = 1000
m_csTcpClient.SendTimeout = 1000
readBytes = New Byte(m_csTcpClient.ReceiveBufferSize - 1) {}
m_csTcpClient.Connect(m_csIPEndPoint)
m_csTcpClient.Client.IOControl(IOControlCode.KeepAliveValues, KeepAlive, Nothing)
m_csNetworkStream = m_csTcpClient.GetStream()
m_csNetworkStream.BeginRead(readBytes, 0, readBytes.Length, AddressOf EndRead, Nothing)
m_bolISActive = True
RaiseEvent LogMsg(New Exception("连接成功"))
Catch ex As Exception
Throw ex
End Try
Return True
End Function
''' <summary>
''' 断开连接
''' </summary>
Public Sub DisConnect()
Dispose(True)
End Sub
''' <summary>
''' KeepAlive函数参数说明
''' </summary>
''' <param name="keepAliveTime">开始首次KeepAlive探测前的TCP空闭时间</param>
''' <param name="keepAliveInterval">两次KeepAlive探测间的时间间隔</param>
''' <param name="onOff">是否开启KeepAlive,默认开启</param>
''' <returns></returns>
Private Function KeepAlive(Optional ByVal keepAliveTime As Integer = 1000,
Optional ByVal keepAliveInterval As Integer = 100,
Optional ByVal onOff As Integer = 1) As Byte()
Dim buffer(11) As Byte
BitConverter.GetBytes(onOff).CopyTo(buffer, 0)
BitConverter.GetBytes(keepAliveTime).CopyTo(buffer, 4)
BitConverter.GetBytes(keepAliveInterval).CopyTo(buffer, 8)
Return buffer
End Function
''' <summary>
''' 在建立连接的情况下发送消息
''' </summary>
''' <param name="msg"></param>
''' <returns></returns>
Public Function SendMsg(ByVal msg As String) As Boolean
If m_bolISActive = False Then
Return False
End If
Dim result As Boolean = False
Try
Dim buff() As Byte = Encoding.Default.GetBytes(msg)
m_csNetworkStream.Write(buff, 0, buff.Length)
result = True
Catch
Throw
End Try
Return result
End Function
''' <summary>
''' 有互斥资源
''' 接收数据,远程连接断开,远程程序关闭,本地连接断开,都会按顺序调用进来;因为连接关闭后不再调用BeginRead
''' </summary>
''' <param name="ar"></param>
Private Sub EndRead(ByVal ar As IAsyncResult)
SyncLock tcpClientLock
If m_bolISActive Then '如果本地主动断开就不会进入
Try
Dim count As Integer = m_csNetworkStream.EndRead(ar)
If count > 0 Then
Dim recvStr As String = Encoding.Default.GetString(readBytes, 0, count)
RaiseEvent RecvMsgEvent(recvStr)
readBytes = New Byte(m_csTcpClient.ReceiveBufferSize - 1) {}
m_csNetworkStream.BeginRead(readBytes, 0, readBytes.Length, AddressOf EndRead, Nothing)
Else '远程客户端主动断开
LocalClientClose("TcpServer关闭")
End If
Catch ex As Exception '网线断开的时候会触发此事件
LocalClientClose("网线断开")
End Try
End If
End SyncLock
End Sub
''' <summary>
''' 远程连接断开后(点关闭断开,程序退出断开)本地连接处理
''' </summary>
Private Sub LocalClientClose(ByVal strType As String)
m_bolISActive = False
DisposeEx()
Dim param As String = strType & " " & m_strIP & " " & m_intPort
RaiseEvent DisconnectEvent(param)
If ISBreaklineReconnection Then
ReConnect()
End If
End Sub
Protected Overrides Sub Dispose(disposing As Boolean)
SyncLock tcpClientLock
If m_bolISActive Then
m_bolISActive = False
DisposeEx()
RaiseEvent DisconnectEvent("主动退出")
End If
End SyncLock
End Sub
''' <summary>
''' 由Dispose和LocalClientClose调用
''' </summary>
Private Sub DisposeEx()
If m_csNetworkStream IsNot Nothing Then
m_csNetworkStream.Dispose()
m_csNetworkStream = Nothing
End If
If m_csTcpClient IsNot Nothing Then
m_csTcpClient.Close()
m_csTcpClient = Nothing
End If
End Sub
End Class
c# VB.NET TcpClientHelper带掉线事件
于 2022-01-14 23:09:52 首次发布