'***************************************************************************
|
'* ClassTCPClient *
|
'* *
|
'* This class manages the TCP connection with an E301 module. *
|
'* It tries to keep the connection alive checking continously it by *
|
'* sending pings. If the connection is lost it tries to connect again. *
|
'* Once connected, this class provides a function to send data to the *
|
'* E301 and an event to trap the data received. *
|
'* *
|
'* EQUITEL C.V. February 2007 ALMDI*
|
'***************************************************************************
|
Imports System
|
Imports System.Net
|
Imports System.Net.Sockets
|
Imports System.Threading
|
Imports System.Text
|
Imports System.IO
|
Imports System.Net.NetworkInformation
|
Imports System.Globalization
|
Imports System.Timers
|
|
Public Class ClassTCPClient
|
|
#Region "Definitions"
|
'Time between pings to the destination IP in miliseconds
|
Private Const CheckingTime As Integer = 3000
|
#End Region
|
|
#Region "Fields"
|
Private mStream As Stream
|
Private mHostIP As String
|
Private mHostPort As String
|
Private mReceivingThread As Thread
|
Private mTcpClient As TcpClient
|
Private WithEvents mPingClient As New Ping()
|
Private WithEvents mTimerPing As New System.Timers.Timer
|
#End Region
|
|
#Region "Events"
|
Public Event ConnectionTerminated As EventHandler
|
Public Event DataReceived As TCPDataReceivedEventHandler
|
Public Event ConnectionSuccesful As EventHandler
|
Public Event ConnectionFailed As EventHandler
|
Public Event ConnectionLost As EventHandler
|
|
Protected Overridable Sub OnConnectionTerminated()
|
RaiseEvent ConnectionTerminated(Me, New EventArgs)
|
End Sub
|
|
Protected Overridable Sub OnConnectionSuccessful()
|
RaiseEvent ConnectionSuccesful(Me, New EventArgs)
|
End Sub
|
|
Protected Overridable Sub OnConnectionFailed()
|
RaiseEvent ConnectionFailed(Me, New EventArgs)
|
End Sub
|
|
Protected Overridable Sub OnConnectionLost()
|
RaiseEvent ConnectionLost(Me, New EventArgs)
|
End Sub
|
|
Protected Overridable Sub OnDataReceived(ByVal Data() As Byte, ByVal Size As Integer)
|
Dim e As New TCPDataReceivedEventArgs
|
e.Data = Data
|
e.Lenght = Size
|
RaiseEvent DataReceived(Me, e)
|
End Sub
|
#End Region
|
|
#Region "Properties"
|
|
Public Property HostIP() As String
|
Get
|
HostIP = mHostIP
|
End Get
|
Set(ByVal Value As String)
|
mHostIP = Value
|
End Set
|
End Property
|
|
Public Property HostPort() As String
|
Get
|
HostPort = mHostPort
|
End Get
|
Set(ByVal Value As String)
|
mHostPort = Value
|
End Set
|
End Property
|
|
Public ReadOnly Property Connected() As Boolean
|
Get
|
Connected = mTcpClient.Connected
|
End Get
|
End Property
|
|
#End Region
|
|
#Region "Methods"
|
|
'Constructor
|
Public Sub New(ByVal Ip As String, ByVal ControlPort As Integer)
|
mHostIP = Ip
|
mHostPort = ControlPort.ToString
|
TryInitConnection()
|
End Sub
|
|
Private Sub OnEndTryingConnection(ByVal Ar As IAsyncResult)
|
If Ar.IsCompleted Then
|
If mTcpClient.Connected Then
|
'The connection has been possible
|
'Stream to send packets
|
mStream = mTcpClient.GetStream()
|
'Thread to read incoming packets
|
mReceivingThread = New Thread(AddressOf ReadData)
|
mReceivingThread.Start()
|
'Start the connection status checking
|
mTimerPing.Start()
|
OnConnectionSuccessful()
|
Else
|
'The connection is not possible
|
mTimerPing.Stop()
|
OnConnectionFailed()
|
'Let's try again
|
TryInitConnection()
|
End If
|
End If
|
End Sub
|
|
|
Public Sub TryInitConnection()
|
'Tries to establish a TCP connection with the E301 module
|
Dim RequestCallback As AsyncCallback
|
Dim State As Object
|
Dim ReturnValue As IAsyncResult
|
|
mTcpClient = New TcpClient()
|
mTcpClient.ReceiveTimeout = 0 'Waits forever for incoming packets
|
mTimerPing.Interval = CheckingTime
|
RequestCallback = New AsyncCallback(AddressOf OnEndTryingConnection)
|
State = New Object
|
ReturnValue = mTcpClient.BeginConnect(HostIP, CInt(HostPort), RequestCallback, State)
|
End Sub
|
|
Public Sub Disconnect()
|
mReceivingThread.Abort()
|
mTimerPing.Stop()
|
mStream.Close()
|
mTcpClient.Close()
|
End Sub
|
|
Public Sub SendData(ByVal Data() As Byte)
|
If Not (mStream Is Nothing) Then
|
mStream.Write(Data, 0, Data.Length)
|
End If
|
End Sub
|
|
Private Sub ReadData()
|
Dim ReadBuffer() As Byte
|
Dim BytesLeidos As Integer
|
Dim Ex As System.Net.Sockets.SocketException
|
While True
|
Try
|
ReadBuffer = New Byte(100) {}
|
'Wait until data arrives
|
BytesLeidos = mStream.Read(ReadBuffer, 0, ReadBuffer.Length)
|
'Data has arrived...
|
OnDataReceived(ReadBuffer, BytesLeidos)
|
Application.DoEvents()
|
Catch e As IOException
|
'Some error... the conection is lost
|
Ex = e.InnerException
|
Console.WriteLine("ErrorCode: " & Ex.ErrorCode.ToString)
|
Console.WriteLine("ERROR: " & Ex.ToString)
|
OnConnectionTerminated()
|
Exit While
|
End Try
|
End While
|
End Sub
|
|
Private Sub OnTimerPingFired(ByVal Sender As Object, ByVal e As System.Timers.ElapsedEventArgs) Handles mTimerPing.Elapsed
|
'Send a ping and wait for a response at the most for the time between
|
'checkings minus one second (and no more than 10 seconds).
|
'This is done in order to not overlap the
|
'processes when the connection is lost. If there is no connection, the waiting
|
'process of one ping mus be terminated before sending a new one.
|
Dim WaitingTime As Integer
|
WaitingTime = CheckingTime - 1000
|
If WaitingTime > 10000 Then WaitingTime = 10000
|
Try
|
mPingClient.SendAsync(mHostIP, WaitingTime, Nothing)
|
Catch
|
End Try
|
End Sub
|
|
Private Sub OnPingClientResponse(ByVal Sender As Object, ByVal e As System.Net.NetworkInformation.PingCompletedEventArgs) Handles mPingClient.PingCompleted
|
'Treats the response of the ping agent
|
Dim NoPingResponse As Boolean = False
|
|
If e.Error Is Nothing Then
|
If e.Reply.Status = IPStatus.TimedOut Then
|
NoPingResponse = True
|
End If
|
Else
|
NoPingResponse = True
|
End If
|
|
If NoPingResponse Then
|
OnConnectionFailed()
|
Disconnect()
|
TryInitConnection()
|
End If
|
End Sub
|
#End Region
|
|
End Class
|