Friend clients As New Hashtable()
Friend listener As TcpListener
Friend listenerThread As Threading.Thread
Friend client As TcpClient
Friend readBuffer(READ_BUFFER_SIZE) As Byte
'CONNECT AS A SERVER:
listenerThread = New Threading.Thread(AddressOf DoListen)
listenerThread.Start()
...
Friend Sub DoListen()
Try
' Listen for new connections.
listener = New System.Net.Sockets.TcpListener(System.Net.IPAddress.Any, CInt(sPort))
listener.Start()
Do While Not shuttingDown
' Create a new user connection using TcpClient returned by
' TcpListener.AcceptTcpClient()
Dim client As New UserConnection(listener.AcceptTcpClient)
' Create an event handler to allow the UserConnection to communicate
' with the window.
AddHandler client.LineReceived, AddressOf OnLineReceived
UpdateStatus("New connection: waiting for login")
Loop 'Until False
Catch ex As Exception
UpdateStatus("FEHLER: " & ex.Message)
Call WriteErrorLog(ex.GetType.ToString & " - " & ex.Message & " (4)")
Finally
shuttingDown = False
End Try
End Sub
'CONNECT AS A CLIENT:
...
ElseIf m_Connstate.cTyp = cTyp.Client And m_Connstate.cState = cState.NotConnected Then 'ElseIf Button1.Text = "connect" Then
If GetInternetConnectedState() = False Then MsgBox("Es besteht keine Internet-Verbindung!", MsgBoxStyle.Exclamation, Me.Text)
Try
' The TcpClient is a subclass of Socket, providing higher level functionality like streaming.
client = New System.Net.Sockets.TcpClient(ResolveDNS(sIP), CInt(sPort))
' Start an asynchronous read invoking DoRead to avoid lagging the user interface.
client.GetStream.BeginRead(readBuffer, 0, READ_BUFFER_SIZE, AddressOf DoRead, Nothing)
' Make sure the window is showing before popping up connection dialog.
Me.Show()
SendData("CONNECT" & SepChar & sUserName) 'AttemptLogin()
m_Connstate.cState = cState.Connected
Catch Ex As Exception
MsgBox("Server not found.", MsgBoxStyle.Exclamation, Me.Text)
m_Connstate.cState = cState.NotConnected
End Try
...
' This is the event handler for the UserConnection when it receives a full line.
' Parse the cammand and parameters and take appropriate action.
Private Sub OnLineReceived(ByVal sender As UserConnection, ByVal data As String)
Dim dataArray() As String
' Message parts are divided by "|" Break the string into an array accordingly.
dataArray = data.Split(CChar(SepChar))
' dataArray(0) is the command.
Select Case dataArray(0)
Case "CONNECT"
ConnectUser(dataArray(1), sender)
Case "CHAT"
SendChat(dataArray(1), sender)
Case "DISCONNECT"
DisconnectUser(sender)
Case "REQUESTUSERS"
ListUsers(sender)
Case Else
UpdateStatus("unknown msg:" & data)
End Select
End Sub
...
' This is the callback function for TcpClient.GetStream.Begin to get an asynchronous read.
Private Sub DoRead(ByVal ar As IAsyncResult)
Dim BytesRead As Integer
Dim strMessage As String
Try
' Finish asynchronous read into readBuffer and return number of bytes read.
BytesRead = client.GetStream.EndRead(ar)
If BytesRead < 1 Then
' If no bytes were read server has close. Disable input window.
MarkAsDisconnected()
Exit Sub
End If
' Convert the byte array the message was saved into
strMessage = System.Text.Encoding.UTF8.GetString(readBuffer, 0, BytesRead)
'strMessage = DeMaskUnicode(strMessage)
'MsgBox("Server schickt: " & strMessage)
Static Buffer As String
Dim msgString As String
msgString = Buffer & strMessage
Buffer = ""
Dim sFeld() As String
sFeld = Split(msgString, Chr(10))
Dim i As Integer
For i = sFeld.GetLowerBound(0) To sFeld.GetUpperBound(0)
If Len(sFeld(i)) = 0 Then Exit For
sFeld(i) = Replace(sFeld(i), Chr(13), vbCrLf)
If Strings.Right(sFeld(i), 1) = Chr(10) Then
ProcessCommands(Replace(sFeld(i), vbCrLf, ""))
Else
Buffer = Buffer & sFeld(i)
End If
Next
' Start a new asynchronous read into readBuffer.
client.GetStream.BeginRead(readBuffer, 0, READ_BUFFER_SIZE, AddressOf DoRead, Nothing)
Catch ex As System.IO.IOException
MarkAsDisconnected()
Call WriteErrorLog(ex.GetType.ToString & " - " & ex.Message & " (5)")
Catch ex As Exception
MsgBox(ex.GetType.ToString & " ---> " & ex.Message)
End Try
End Sub
...
' This subroutine sends a message to all attached clients except the sender.
Private Sub SendToClients(ByVal strMessage As String, ByVal sender As UserConnection)
Dim client As UserConnection
Dim entry As DictionaryEntry
' All entries in the clients Hashtable are UserConnection so it is possible
' to assign it safely.
For Each entry In clients
client = CType(entry.Value, UserConnection)
' Exclude the sender.
If client.Name <> sender.Name Then
client.SendData(strMessage)
End If
Next
End Sub
...
' Use a StreamWriter to send a message to server.
Private Sub SendData(ByVal data As String)
SyncLock client.GetStream
If m_Connstate.cTyp = cTyp.Server And m_Connstate.cState = cState.Connected And clients.Count > 0 Then
Call OnLineReceived(DirectCast(clients(sUserName), UserConnection), Replace(data, vbCrLf, ""))
Exit Sub
End If
Dim writer As New IO.StreamWriter(client.GetStream)
writer.WriteLine(data)
writer.Flush()
End SyncLock
End Sub
...
' The UserConnection class encapsulates the functionality of a TcpClient connection
' with streaming for a single user.
Public Class UserConnection
Implements IDisposable
Private client As TcpClient
Private readBuffer(READ_BUFFER_SIZE) As Byte
Private strName As String
Const READ_BUFFER_SIZE As Integer = 25500
Private PublicIP As String
' The Name property uniquely identifies the user connection.
Public Property Name() As String
Get
Return strName
End Get
Set(ByVal Value As String)
strName = Value
End Set
End Property
Public ReadOnly Property PublicIPAddress() As String
Get
If PublicIP = String.Empty Then
Try
' Get the clients IP address using Client property
Dim ipend As Net.IPEndPoint = DirectCast(client.Client.RemoteEndPoint, Net.IPEndPoint)
If Not ipend Is Nothing Then
PublicIP = ipend.Address.ToString & ":" & ipend.Port.ToString
End If
Catch ex As System.ObjectDisposedException
PublicIP = String.Empty
Catch ex As SocketException
PublicIP = String.Empty
End Try
End If
Return PublicIP
End Get
End Property
Public Sub Dispose() Implements IDisposable.Dispose
DirectCast(client, IDisposable).Dispose()
End Sub
' Overload the New operator to set up a read thread.
Public Sub New(ByVal client As TcpClient)
Me.client = client
' This starts the asynchronous read thread. The data will be saved into readBuffer.
Me.client.GetStream.BeginRead(readBuffer, 0, READ_BUFFER_SIZE, AddressOf StreamReceiver, Nothing)
'Me.client.GetStream.Read(readBuffer, 0, READ_BUFFER_SIZE) 'Synchron
End Sub
Public Event LineReceived(ByVal sender As UserConnection, ByVal Data As String)
' This subroutine uses a StreamWriter to send a message to the user.
Public Sub SendData(ByVal Data As String)
' Synclock ensure that no other threads try to use the stream at the same time.
'MsgBox(Data)
'Threading.Thread.Sleep(10)
SyncLock client.GetStream
Dim writer As New IO.StreamWriter(client.GetStream)
writer.WriteLine(Data)
' Make sure all data is sent now.
writer.Flush()
End SyncLock
End Sub
' This is the callback function for TcpClient.GetStream.Begin. It begins an
' asynchronous read from a stream.
Private Sub StreamReceiver(ByVal ar As IAsyncResult)
Dim BytesRead As Integer
Static strMessage As String
Try
' Ensure that no other threads try to use the stream at the same time.
SyncLock client.GetStream
' Finish asynchronous read into readBuffer and get number of bytes read.
BytesRead = client.GetStream.EndRead(ar)
End SyncLock
' Convert the byte array the message was saved into
strMessage = Encoding.UTF8.GetString(readBuffer, 0, BytesRead)
'MsgBox("Client schickt " & strMessage)
Static Buffer As String
Dim msgString As String
msgString = Buffer & strMessage
Buffer = ""
Dim sFeld() As String
sFeld = Split(msgString, Chr(10))
Dim i As Integer
For i = sFeld.GetLowerBound(0) To sFeld.GetUpperBound(0)
If Len(sFeld(i)) = 0 Then Exit For
sFeld(i) = Replace(sFeld(i), Chr(13), vbCrLf)
If Strings.Right(sFeld(i), 1) = Chr(10) Then
RaiseEvent LineReceived(Me, Strings.Left(sFeld(i), Len(sFeld(i)) - 2))
Else
Buffer = Buffer & sFeld(i)
End If
Next
' Ensure that no other threads try to use the stream at the same time.
SyncLock client.GetStream
' Start a new asynchronous read into readBuffer.
client.GetStream.BeginRead(readBuffer, 0, READ_BUFFER_SIZE, AddressOf StreamReceiver, Nothing)
End SyncLock
Catch ex As Exception
Call WriteErrorLog(ex.GetType.ToString & " - " & ex.Message & " (9)")
End Try
End Sub
End Class