Imports System.Text
Imports System.IO
Imports System.Net
Imports System.Net.Sockets
Namespace Network
Public Class Cliente
Implements IDisposable
#Region " Declaraciones "
Private Socket As Socket
Private CallBackHandler As AsyncCallback
Private ClientList As ArrayList = ArrayList.Synchronized(New ArrayList())
Private objEndPoint As IPEndPoint
Private ID As Integer = 0
Private BufData As Byte() = New Byte(65536) {}
Public Event DatosRecibidos(ByVal Datos() As Byte, ByVal SocketID As Integer)
Public Event ErrorCatched(ByVal msg As String)
Public Event Desconectado()
Public Event Conectado(ByVal SocketID As Integer)
#End Region
#Region " Procedimientos "
Public Sub Conectar(ByVal vsIp As String, ByVal viPuerto As Integer)
Try
If Socket IsNot Nothing Then
If Socket.Connected Then
Call Desconectar()
End If
End If
Socket = New Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)
Socket.NoDelay = True
Socket.DontFragment = False
Socket.LingerState.Enabled = True
Socket.LingerState.LingerTime = 100
Socket.SendBufferSize = 65536
Socket.ReceiveBufferSize = 65536
Dim endpoint As Net.IPEndPoint
endpoint = New IPEndPoint(IPAddress.Parse(vsIp), viPuerto)
Socket.Connect(endpoint)
If Socket.Connected Then
objEndPoint = CType(Socket.RemoteEndPoint, IPEndPoint)
Call EsperaDeDatos()
End If
Catch ex As SocketException
RaiseEvent ErrorCatched(ex.Message)
End Try
End Sub
Public Sub Desconectar()
Try
If Socket IsNot Nothing Then
If Socket.Connected Then
Socket.Disconnect(True)
End If
Socket.Close()
Socket = Nothing
End If
RaiseEvent Desconectado()
Catch SE As SocketException
RaiseEvent ErrorCatched(SE.Message)
End Try
End Sub
Public Sub Desconectar(ByVal SocketID As Integer)
DropClient(GetSocketPacket(SocketID), False, False)
End Sub
Public Function EnviarMensaje(ByVal SocketID As Integer, ByVal Datos() As Byte) As Boolean
Try
If GetSocketPacket(SocketID).mClientSocket.Connected Then
GetSocketPacket(SocketID).mClientSocket.Send(Datos)
Return (True)
Else
Return (False)
End If
Catch
Return (False)
End Try
End Function
Public Function EnviarMensaje(ByVal SocketID As Integer, ByVal Mensaje As String) As Boolean
Try
If GetSocketPacket(SocketID).mClientSocket.Connected Then
Dim NetStream As New NetworkStream(GetSocketPacket(SocketID).mClientSocket)
Dim SocketStream As New StreamWriter(NetStream)
SocketStream.Write(Mensaje)
SocketStream.Flush()
Return (True)
Else
Return (False)
End If
Catch
Return (False)
End Try
End Function
#End Region
#Region " Procedimientos Privados "
Private Sub EsperaDeDatos()
Try
If CallBackHandler Is Nothing Then
CallBackHandler = New AsyncCallback(AddressOf OnDataReceived)
End If
Dim socketId As Integer = 1
If ClientList.Count > 0 Then
socketId = TryCast(ClientList(ClientList.Count - 1), SocketPacket).mSocketID + 1
End If
Dim ConnectedClient As New SocketPacket(Socket, socketId)
ClientList.Add(ConnectedClient)
ID += 1
Socket.BeginReceive(BufData, 0, BufData.Length, SocketFlags.None, CallBackHandler, Socket)
RaiseEvent Conectado(ConnectedClient.mSocketID)
Catch SE As SocketException
RaiseEvent ErrorCatched(SE.Message)
Catch E As Exception
RaiseEvent ErrorCatched(E.Message)
End Try
End Sub
Private Sub OnDataReceived(ByVal Asyn As IAsyncResult)
Try
Dim ConnectedClient As SocketPacket = DirectCast(Asyn.AsyncState, SocketPacket)
If Not ConnectedClient.mClientSocket.Connected Then
Return
End If
Dim CollectedDataLength As Integer = Socket.EndReceive(Asyn)
If CollectedDataLength = 0 Then
If ConnectedClient.mClientSocket.Connected Then
ConnectedClient.mClientSocket.Disconnect(False)
End If
ConnectedClient.mClientSocket.Close()
RaiseEvent Desconectado()
Else
RaiseEvent DatosRecibidos(BufData, ConnectedClient.mSocketID)
EsperaDeDatos()
End If
Catch generatedExceptionName As ObjectDisposedException
RaiseEvent Desconectado()
Catch SE As SocketException
If SE.ErrorCode = 10054 Then
RaiseEvent Desconectado()
Else
RaiseEvent ErrorCatched(SE.Message)
End If
Catch E As Exception
RaiseEvent ErrorCatched(E.Message)
End Try
End Sub
Private Sub DropClient(ByVal DisposedSocket As SocketPacket, ByVal DisconnectedRemotly As Boolean, ByVal DisconnectedForcibly As Boolean) 'tirar clientes
Try
DisposedSocket.mClientSocket.Shutdown(SocketShutdown.Both)
Catch
End Try
Dim IsRemoved As Boolean = False
SyncLock ClientList.SyncRoot
Try
Dim SckID As Integer = 0
While Not IsRemoved AndAlso (SckID < ClientList.Count)
Dim ClientSocket As SocketPacket = DirectCast(ClientList(SckID), SocketPacket)
If ClientSocket.mClientSocket Is DisposedSocket.mClientSocket Then
ClientList.Remove(ClientSocket)
ID -= 1
IsRemoved = True
RaiseEvent Desconectado()
End If
SckID += 1
End While
Catch E As Exception
RaiseEvent ErrorCatched(E.Message)
End Try
End SyncLock
End Sub
Private Function GetSocketPacket(ByVal SocketID As Integer) As SocketPacket ' obtener paquetes del socket
Dim mClientSocket As SocketPacket = Nothing
For Each ClientSocket As SocketPacket In ClientList
If ClientSocket.mSocketID = SocketID Then
mClientSocket = ClientSocket
Exit For
End If
Next
Return (mClientSocket)
End Function
#End Region
#Region "propiedades"
Public ReadOnly Property IsConectado() As Boolean
Get
Return Socket.Connected
End Get
End Property
Public ReadOnly Property RemoteEndPoint() As System.Net.IPEndPoint
Get
Return objEndPoint
End Get
End Property
Public ReadOnly Property TotalConectado As Integer
Get
Return ID
End Get
End Property
#End Region
#Region "Rem -> [ Socket Packet Helper Class ]"
Class SocketPacket
Friend ReadOnly mClientSocket As Socket
Friend ReadOnly mSocketID As Integer
Public Sub New(ByVal ClientSocket As Socket, ByVal SocketID As Integer)
mClientSocket = ClientSocket
mSocketID = SocketID
End Sub
End Class
#End Region
#Region " IDisposable Support "
Private disposedValue As Boolean = False ' Para detectar llamadas redundantes
' IDisposable
Protected Overridable Sub Dispose(ByVal disposing As Boolean)
If Not Me.disposedValue Then
If disposing Then
' TODO: Liberar otro estado (objetos administrados).
End If
' TODO: Liberar su propio estado (objetos no administrados).
' TODO: Establecer campos grandes como Null.
End If
Me.disposedValue = True
End Sub
' Visual Basic agregó este código para implementar correctamente el modelo descartable.
Public Sub Dispose() Implements IDisposable.Dispose
' No cambie este código. Coloque el código de limpieza en Dispose (ByVal que se dispone como Boolean).
Dispose(True)
GC.SuppressFinalize(Me)
End Sub
#End Region
End Class
End Namespace