Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- Imports System.Net
- Imports System.Net.Sockets
- Imports System.Text
- Imports System.Threading
- Imports System.Collections.Concurrent
- Imports System.IO
- Public Class Server
- Public Event ServerStarted(ByVal Port As UShort)
- Public Event NewClientConnected(ByVal SessionID As String, ByVal Time As Date)
- Public Event ClientDisconnected(ByVal SessionID As String, ByVal Time As Date)
- Public Event DataRecieved(ByVal Data() As Byte, ByVal SessionID As String, ByVal Time As Date)
- Public Event ServerStoping(ByVal StopTime As Date, ByVal Time As TimeSpan)
- Public Event ServerDebug(ByVal Ex As ServerException)
- Private Shared ValidIdChars As String = "0123456789ABCDEF"
- Private Shared Rnd As New Random
- Private Clients As New ConcurrentDictionary(Of String, ConnectedClient)
- Private _UpTime As New Stopwatch
- Private _PreviousUpTime As TimeSpan
- Private ListeningThread As Threading.Thread
- Private NewTCP As TcpListener = Nothing
- Private _Port As UShort
- Public ReadOnly Property UpTime() As TimeSpan
- Get
- If _UpTime.IsRunning Then Return _UpTime.Elapsed Else Return New TimeSpan(0)
- End Get
- End Property
- Public ReadOnly Property Count() As UInteger
- Get
- SyncLock Clients
- Return Clients.Count
- End SyncLock
- End Get
- End Property
- Public Sub Start(ByVal Port As UShort)
- If NewTCP Is Nothing Then
- _Port = Port
- ListeningThread = New Threading.Thread(AddressOf Listen)
- ListeningThread.Start()
- Else
- RaiseEvent ServerDebug(New ServerException(ServerExceptions.AlreadyRunning))
- End If
- End Sub
- Public Sub EndSession(ByVal SessionID As String)
- If Clients.ContainsKey(SessionID) Then
- If Clients(SessionID).Close() = False Then
- Dim EndThread As New Threading.Thread(Sub()
- If Clients(SessionID).Close() = False Then
- End If
- End Sub)
- EndThread.Start()
- End If
- Else
- RaiseEvent ServerDebug(New ServerException(ServerExceptions.DisconnectFailed, {SessionID}))
- End If
- End Sub
- Public Sub Purge()
- For Each K As String In Clients.Keys
- EndSession(K)
- Next
- End Sub
- Public Sub [Stop]()
- If NewTCP IsNot Nothing Then
- _UpTime.Stop()
- NewTCP.Stop()
- ListeningThread.Abort()
- For Each K As String In Clients.Keys
- EndSession(K)
- Next
- _PreviousUpTime = _UpTime.Elapsed
- RaiseEvent ServerStoping(DateTime.Now, _PreviousUpTime)
- NewTCP = Nothing
- Else
- RaiseEvent ServerDebug(New ServerException(ServerExceptions.NotRunning, {}))
- End If
- End Sub
- Private Sub EstablishedNewClient(ByVal Client As ConnectedClient, ByVal Time As Date)
- Dim NewID As String
- Do
- NewID = String.Empty
- For i = 1 To 24
- NewID &= ValidIdChars(Rnd.Next(0, 16))
- Next
- Loop Until Clients.TryAdd(NewID, Client)
- Client.AssignID(NewID)
- RaiseEvent NewClientConnected(NewID, Time)
- Client.BeginReceive()
- End Sub
- Private Sub DisconnectedClient(ByVal SessionID As String, ByVal Time As Date)
- Try
- Dim CC As ConnectedClient = Clients(SessionID)
- If Clients.TryRemove(SessionID, CC) Then
- RaiseEvent ClientDisconnected(SessionID, Time)
- Else
- RaiseEvent ServerDebug(New ServerException(ServerExceptions.DisconnectFailed, {SessionID}))
- End If
- Catch ex As Exception
- RaiseEvent ServerDebug(New ServerException(ex))
- End Try
- End Sub
- Private Sub RecievedData(ByVal SessionID As String, ByVal Data() As Byte, ByVal Time As Date)
- RaiseEvent DataRecieved(Data, SessionID, Time)
- End Sub
- Public Sub Send(ByVal SessionID As String, ByVal Data() As Byte)
- Try
- Clients(SessionID).Send(Data)
- Catch ex As Exception
- RaiseEvent ServerDebug(New ServerException(ServerExceptions.FailedToSend, {SessionID}))
- End Try
- End Sub
- Public Sub Broadcast(ByVal Data() As Byte)
- Dim Failed As New List(Of String)
- For Each K As ConnectedClient In Clients.Values
- Try
- K.Send(Data)
- Catch ex As Exception
- Failed.Add(K.SessionID)
- End Try
- Next
- If Failed.Count > 0 Then _
- RaiseEvent ServerDebug(New ServerException(ServerExceptions.IncompleteBroadcast, Failed.ToArray))
- End Sub
- Public Sub Broadcast(ByVal SessionIDs() As String, ByVal Data() As Byte, _
- Optional ByVal BroadcastType As BroadcastType = BroadcastType.BlackList)
- Dim Failed As New List(Of String)
- For Each K As ConnectedClient In Clients.Values
- Try
- If BroadcastType = Server.BroadcastType.WhiteList _
- Then If SessionIDs.Contains(K.SessionID) Then K.Send(Data) _
- Else If SessionIDs.Contains(K.SessionID) Then Continue For Else K.Send(Data)
- Catch ex As Exception
- Failed.Add(K.SessionID)
- End Try
- Next
- If Failed.Count > 0 Then
- If BroadcastType = Server.BroadcastType.WhiteList _
- Then RaiseEvent ServerDebug( _
- New ServerException(ServerExceptions.IncompleteWhiteListBroadcast, Failed.ToArray)) _
- Else RaiseEvent ServerDebug( _
- New ServerException(ServerExceptions.IncompleteBlackListBroadcast, Failed.ToArray))
- End If
- End Sub
- Private Sub Listen()
- NewTCP = New TcpListener(IPAddress.Any, _Port)
- NewTCP.Start()
- RaiseEvent ServerStarted(_Port)
- _UpTime.Restart()
- While True
- Try
- Dim NewClient As New ConnectedClient(NewTCP.AcceptTcpClient)
- AddHandler NewClient.Established, AddressOf EstablishedNewClient
- AddHandler NewClient.Disconnected, AddressOf DisconnectedClient
- AddHandler NewClient.DataReceived, AddressOf RecievedData
- NewClient.ProcessClientConnected()
- Catch ex As Exception
- End Try
- End While
- End Sub
- Public Enum BroadcastType
- WhiteList
- BlackList
- End Enum
- Public Enum ServerExceptions
- InvalidSession
- AlreadyRunning
- NotRunning
- IncompleteBroadcast
- IncompleteWhiteListBroadcast
- IncompleteBlackListBroadcast
- FailedToSend
- DisconnectFailed
- [Default]
- End Enum
- Public Class ServerException
- Inherits Exception
- Private Msg As String = String.Empty
- Private SessionID() As String
- Private Type As ServerExceptions
- Public ReadOnly Property Sessions() As String()
- Get
- Return SessionID
- End Get
- End Property
- Public Sub New(ByVal Ex As Exception)
- Type = ServerExceptions.Default
- MyBase.HResult = Ex.HResult
- Msg = Ex.Message
- End Sub
- Public Sub New(ByVal ExceptionType As ServerExceptions, Optional ByVal SessionID() As String = Nothing)
- Type = ExceptionType
- Select Case ExceptionType
- Case ServerExceptions.AlreadyRunning
- Msg = "Server is already running"
- Case ServerExceptions.NotRunning
- Msg = "Server isn't running"
- Case ServerExceptions.InvalidSession
- Me.SessionID = SessionID
- Msg = "Server does not contain these sessions: " & SessionID(0)
- For i = 1 To SessionID.Length - 1
- Msg &= ", " & SessionID(i)
- Next
- Case ServerExceptions.DisconnectFailed
- Me.SessionID = SessionID
- If SessionID.Length > 0 Then
- Msg = "Server was unable to close these sessions: " & SessionID(0)
- If Msg.Length > 1 Then
- For i = 1 To SessionID.Length - 1
- Msg &= ", " & SessionID(i)
- Next
- End If
- End If
- Case ServerExceptions.FailedToSend
- Me.SessionID = SessionID
- If SessionID.Length > 0 Then
- Msg = "Server was unable to send to session: " & SessionID(0)
- If Msg.Length > 1 Then
- For i = 1 To SessionID.Length - 1
- Msg &= ", " & SessionID(i)
- Next
- End If
- End If
- Case ServerExceptions.IncompleteBlackListBroadcast
- Me.SessionID = SessionID
- If SessionID.Length > 0 Then
- Msg = "Server was unable to complete blacklist broadcast: " & SessionID(0)
- If Msg.Length > 1 Then
- For i = 1 To SessionID.Length - 1
- Msg &= ", " & SessionID(i)
- Next
- End If
- End If
- Case ServerExceptions.IncompleteWhiteListBroadcast
- Me.SessionID = SessionID
- If SessionID.Length > 0 Then
- Msg = "Server was unable to complete whitelist broadcast: " & SessionID(0)
- If Msg.Length > 1 Then
- For i = 1 To SessionID.Length - 1
- Msg &= ", " & SessionID(i)
- Next
- End If
- End If
- Case ServerExceptions.IncompleteBroadcast
- Me.SessionID = SessionID
- If SessionID.Length > 0 Then
- Msg = "Server was unable to complete broadcast: " & SessionID(0)
- If Msg.Length > 1 Then
- For i = 1 To SessionID.Length - 1
- Msg &= ", " & SessionID(i)
- Next
- End If
- End If
- End Select
- End Sub
- Public Overrides ReadOnly Property Message As String
- Get
- Return Msg
- End Get
- End Property
- End Class
- Public Class ConnectedClient
- Public Event Established(ByVal Client As ConnectedClient, ByVal Time As Date)
- Public Event Disconnected(ByVal SessionID As String, ByVal DateTime As Date)
- Public Event DataReceived(ByVal SessionID As String, ByVal Data() As Byte, ByVal DateTime As Date)
- Private _SessionID As String = String.Empty
- Private ReceiveThread As Threading.Thread
- Private _Client As Socket
- Private Buffer() As Byte
- Public ReadOnly Property SessionID() As String
- Get
- Return _SessionID
- End Get
- End Property
- Public Sub New(ByVal Client As TcpClient)
- _Client = Client.Client
- Buffer = New Byte(_Client.ReceiveBufferSize - 1) {}
- End Sub
- Private Sub _DataReceived(ByVal Data() As Byte, ByVal Time As Date)
- RaiseEvent DataReceived(SessionID, Data, Time)
- SyncLock _Client
- If _Client.Connected Then BeginReceive()
- End SyncLock
- End Sub
- Public Sub ProcessClientConnected()
- RaiseEvent Established(Me, DateTime.Now)
- End Sub
- Public Sub AssignID(ByVal SessionID As String)
- _SessionID = SessionID
- End Sub
- Public Sub Send(ByVal Data() As Byte)
- Try
- _Client.BeginSend(Data, 0, Data.Length, SocketFlags.None, New AsyncCallback(AddressOf OnSend), _Client)
- Catch ex As Exception
- End Try
- End Sub
- Private Sub OnSend(ByVal ar As IAsyncResult)
- Try
- Dim client As Socket = ar.AsyncState
- client.EndSend(ar)
- Catch ex As Exception
- End Try
- End Sub
- Public Function Close() As Boolean
- Try
- ReceiveThread.Abort()
- _Client.Close()
- _Client.Dispose()
- RaiseEvent Disconnected(SessionID, DateTime.Now)
- Return True
- Catch ex As Exception
- Return False
- End Try
- End Function
- Public Sub BeginReceive()
- If _Client.Connected Then
- ReceiveThread = New Threading.Thread(Sub()
- Dim Failed As Boolean = False
- Dim Count As Integer
- Dim R() As Byte
- Using MS As New MemoryStream()
- Do
- Try
- Count = _Client.Receive(Buffer)
- MS.Write(Buffer, 0, Count)
- Catch ex As Exception
- Failed = True
- End Try
- Loop Until Count < Buffer.Length
- R = MS.ToArray
- MS.Close()
- End Using
- If Failed OrElse R.Length = 0 Then
- RaiseEvent Disconnected(SessionID, DateTime.Now)
- Else
- _DataReceived(R, DateTime.Now)
- End If
- End Sub)
- ReceiveThread.Start()
- End If
- End Sub
- End Class
- End Class
Advertisement
Add Comment
Please, Sign In to add comment