Código
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