troubleshooting Question

Need help making my tcp server multithreaded

Avatar of Frosty555
Frosty555Flag for Canada asked on
Visual Basic Classic.NET Programming
4 Comments1 Solution2104 ViewsLast Modified:
I'm working on a fairly simple message-based TCP server written in VB.NET 2005. It works roughly like this:

       1) Server is started by creating a TCPListener object and accepting new clients.
       2) A callback is hooked into for when a new client appears
       3) When the callback is triggered, a TCPClient object called "myclient" is initialized, and a networkstream for that client is initialized called "mystream"
       4) A tight loop ensues which constantly calls a "PollForData()" method which listens for incoming data on the mystream stream and processes it via a call to "ProcessReceivedMessage()".
       5) Messages are sent back to the client usually asynchronously in response to receieved messages

I'll post my code but it's a little longwinded.

Now I need the server to support MULTIPLE clients simultaneously, and also properly release resources when clients get terminated / disconnected.

I know I need to take a multithreaded approach to do this but the examples I've seen have been confusing. It looks like I need a separate class to handle each client. Can anyone help me figure out what I need to put into that separate class and how to do the threading?
USAGE OF SERVER:
 
        Dim server as New KCSServer()
        server.StartServer("127.0.0.1", 2222)
        Do While True
            server.PollForData()
            Application.DoEvents()
        Loop
 
 
--------------------------------------
 
 
Imports System.Net.Sockets
Imports System.IO
Imports System.Text
Imports System.Security.Cryptography
Imports System.Net
 
Public Class KCSServer
    Private tcps As TcpListener
    Private client As TcpClient
    Private stream As NetworkStream
 
         ....
 
    Public Sub New()
        Dim port As Int32 = 2222
        Dim ip As String = "127.0.0.1"
        Dim localAddr As IPAddress = IPAddress.Parse(ip)
        tcps = New TcpListener(localAddr, port)
    End Sub
 
    Public Function StartServer(ByVal server As String, ByVal port As Integer) As Boolean
        Try
            tcps.Start()
            tcps.BeginAcceptTcpClient(AddressOf Callback_IncomingClient, 0)
            status = SERVER_STATUS_LISTENING
            StartServer = True
            RaiseEvent Listening()
        Catch ex As Exception
            RaiseEvent ListenFailed(ex.Message)
            StartServer = False
            status = SERVER_STATUS_FAILED
        End Try
    End Function
 
    Private Sub Callback_IncomingClient(ByVal ar As IAsyncResult)
        client = tcps.EndAcceptTcpClient(ar)
        client.ReceiveBufferSize = 5000 * 1024
        stream = client.GetStream()
 
        If Not stream Is Nothing Then
            status = SERVER_STATUS_CONNECTED
            RaiseEvent ClientConnected()
        End If
    End Sub
 
    Public Sub SendMessage(ByVal type As Byte, ByRef data() As Byte, Optional ByVal bSynchronous As Boolean = False)
                 ... do some hashing and processing ...
            allDone = stream.BeginWrite(chunk, 0, chunk.Length, AddressOf Callback_WriteComplete, 0)
 
            If bSynchronous Then
                allDone.AsyncWaitHandle.WaitOne(10000, True)
                stream.EndWrite(allDone)
                If Not allDone.IsCompleted Then
                    Console.WriteLine("Error sending message to client. Took too long.")
                End If
            End If
    End Sub
 
    Public Sub PollForData()
        If status <> SERVER_STATUS_CONNECTED Then Exit Sub
             ... lots of declarations and error checking ...
        While mystream.DataAvailable And myclient.Available >= header.Length + hash.Length
                  ... read in the data via calls imlar to this one:
                       bytesRead = mystream.Read(data, 0, data.Length)
                       ProcessReceivedMessage(data, sizeOfData, typeOfData)                
        End While
 
    Private Sub ProcessReceivedMessage(ByRef message As [Byte](), ByVal size As Integer, ByVal type As Integer)
        Select Case type
            Case 0
                   ... do something in response to message ...
            Case 1
                   ... do something in response to message ...
            Case 2
                   ... do something in response to message ...
        End Select
    End Sub
End Class
Join the community to see this answer!
Join our exclusive community to see this answer & millions of others.
Unlock 1 Answer and 4 Comments.
Join the Community
Learn from the best

Network and collaborate with thousands of CTOs, CISOs, and IT Pros rooting for you and your success.

Andrew Hancock - VMware vExpert
See if this solution works for you by signing up for a 7 day free trial.
Unlock 1 Answer and 4 Comments.
Try for 7 days

”The time we save is the biggest benefit of E-E to our team. What could take multiple guys 2 hours or more each to find is accessed in around 15 minutes on Experts Exchange.

-Mike Kapnisakis, Warner Bros