Hi everyone! My first post here in vb forums. I'm new to sockets programming since I migrated from Winsock and I learn a lot from Atheist. using his code, I can't access the messageReceived() every time a client sends a message on the server. but then I put a code to catch the message on sub doRead() and I can retrieve the message. My problem now is how can I determine if a client is still connected to the server or not so I can delete it on the ConnectedClient ?
ConnectedClient Class:
Server Side:Code:Public Class ConnectedClient Private mClient As System.Net.Sockets.TcpClient Private mUsername As String Private mParentForm As FrmServer Private readThread As System.Threading.Thread Private Const MESSAGE_DELIMITER As Char = ControlChars.Cr Public Event dataReceived(ByVal sender As ConnectedClient, ByVal message As String) Sub New(ByVal client As System.Net.Sockets.TcpClient, ByVal parentForm As FrmServer) mParentForm = parentForm mClient = client readThread = New System.Threading.Thread(AddressOf doRead) readThread.IsBackground = True readThread.Start() End Sub Public Property Username() As String Get Return mUsername End Get Set(ByVal value As String) mUsername = value mParentForm.SetConnectionLabelText(value) End Set End Property Private Sub doRead() Const BYTES_TO_READ As Integer = 255 Dim readBuffer(BYTES_TO_READ) As Byte Dim bytesRead As Integer Dim sBuilder As New System.Text.StringBuilder Do If mClient.GetStream.DataAvailable Then bytesRead = mClient.GetStream.Read(readBuffer, 0, BYTES_TO_READ) If (bytesRead > 0) Then Dim message As String = System.Text.Encoding.UTF8.GetString(readBuffer, 0, bytesRead) mParentForm.SetConnectionLabelText(message) '<----message catcher If (message.IndexOf(MESSAGE_DELIMITER) > -1) Then Dim subMessages() As String = message.Split(MESSAGE_DELIMITER) sBuilder.Append(subMessages(0)) RaiseEvent dataReceived(Me, sBuilder.ToString) sBuilder = New System.Text.StringBuilder If subMessages.Length = 2 Then sBuilder.Append(subMessages(1)) Else For i As Integer = 1 To subMessages.GetUpperBound(0) - 1 RaiseEvent dataReceived(Me, subMessages(i)) Next sBuilder.Append(subMessages(subMessages.GetUpperBound(0))) End If Else sBuilder.Append(message) End If End If End If Loop End Sub Public Sub SendMessage(ByVal msg As String) Dim sw As IO.StreamWriter Try SyncLock mClient.GetStream sw = New IO.StreamWriter(mClient.GetStream) sw.Write(msg) sw.Flush() End SyncLock Catch ex As Exception MessageBox.Show(ex.ToString) End Try End Sub End Class
Note: the server runs on Win7 x64 ultimate and the clients are laptops on win7 x86. I read a comment that the server should be having a static IP address, but when did it together with the clients, It still doesn't work. I am just using a switch for the network.Code:Imports System.Net, System.Net.Sockets, System.IO Public Class FrmServer Private listener As System.Net.Sockets.TcpListener Private listenThread As System.Threading.Thread Private clients As New List(Of ConnectedClient) Private Sub doListen() Dim incomingClient As System.Net.Sockets.TcpClient Do incomingClient = listener.AcceptTcpClient Dim connClient As New ConnectedClient(incomingClient, Me) AddHandler connClient.dataReceived, AddressOf Me.messageReceived clients.Add(connClient) Loop End Sub Public Sub removeClient(ByVal client As ConnectedClient) If clients.Contains(client) Then clients.Remove(client) End If End Sub Private Sub messageReceived(ByVal sender As ConnectedClient, ByVal message As String) MsgBox(message) Dim data() As String = message.Split("|"c) Select Case data(0) Case "CONNECT" If GetClientByName(data(1)) Is Nothing Then sender.SendMessage("You are Connected") sender.Username = data(1) End If Case "DISCONNECT" removeClient(sender) End Select End Sub Private Function GetClientByName(ByVal name As String) As ConnectedClient For Each cc As ConnectedClient In clients If cc.Username = name Then Return cc 'client found, return it. End If Next 'If we've reached this part of the method, there is no client by that name Return Nothing End Function Private Sub FrmServer_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load listener = New System.Net.Sockets.TcpListener(System.Net.IPAddress.Any, 43001) 'The TcpListener will listen for incoming connections at port 43001 listener.Start() 'Start listening. listenThread = New System.Threading.Thread(AddressOf doListen) 'This thread will run the doListen method listenThread.IsBackground = True 'Since we dont want this thread to keep on running after the application closes, we set isBackground to true. listenThread.Start() End Sub Private Sub Btn_Send_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Btn_Send.Click lstlog.Items.Add(txtName.Text & " says " & txtMessage.Text) For Each cc As ConnectedClient In clients cc.SendMessage(txtName.Text & " says " & txtMessage.Text) Next End Sub Private Delegate Sub StringDelegate(ByVal text As String) Sub SetConnectionLabelText(ByVal text As String) If lstlog.InvokeRequired Then Me.Invoke(New StringDelegate(AddressOf SetConnectionLabelText), text) Else Dim Data() As String = text.Split("|"c) Select Case Data(0) Case "CONNECT" lstlog.Items.Add(Data(1) & " is connected.") For Each cc As ConnectedClient In clients cc.SendMessage(Data(1) & " is connected.") Next Case "MESSAGE" lstlog.Items.Add(Data(1) & " says " & Data(2)) For Each cc As ConnectedClient In clients cc.SendMessage(Data(1) & " says " & Data(2)) Next End Select End If End Sub Sub AddClientList(ByVal text As String) If lsvClients.InvokeRequired Then Me.Invoke(New StringDelegate(AddressOf AddClientList), text) Else End If End Sub Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click clients.Item(CInt(lsvClients.SelectedItems(0).Tag)).SendMessage(txtMessage.Text) End Sub End Class




Reply With Quote