asim-ishaq
asim-ishaq

Reputation: 2220

VB.NET Listen for TCP connections without wasting processor usage

I am creating a voice server with VB.NET using TCPListener. To check for incoming connections I have created an infinite loop in Form Load method and whenever a connection is available it accepts it and then creates a new thread to handle communication. Following is the code:

Private WithEvents SR As New SoundRecorder
Private TCPListener As TcpListener

Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
    TCPListener = New TcpListener(Net.IPAddress.Parse(GetIPv4Address), 2021)
    TCPListener.Start()
    While 1
        If TCPListener.Pending = True Then
            Dim voiceCom As New BroadcastSound(TCPListener.AcceptSocket())
            Dim th As New Threading.Thread(AddressOf voiceCom.startCommunication)
            th.Start()
        End If
        Application.DoEvents()
    End While
End Sub

The server works perfectly and honor all connections but the problem is that the processor usage is always 100% because of this server whether any client is connected or not. Is there any better way to listen for incoming connections?

Upvotes: 0

Views: 10438

Answers (2)

user287848
user287848

Reputation: 141

I realize this is quite old, but in my searches for something similar, this was one of the first results.

     Public Class main

        Private client As TcpClient
        Private listener As TcpListener
        Private WithEvents tcpBg As BackgroundWorker

        Private Sub main_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
            tcpBg = New BackgroundWorker
            'Requires a routine that cancels background worker.
            tcpBg.WorkerSupportsCancellation = True
            'ip is most likely from a Textbox.
            Dim adr As Net.IPAddress = Net.IPAddress.Parse(ip)
            listener = New TcpListener(adr, 60000)

            tcpBg.RunWorkerAsync()
        End Sub     

        Private Sub tcpBg_DoWork(ByVal sender As Object, ByVal e As DoWorkEventArgs) Handles tcpBg.DoWork
            listener.Start()
            While tcpBg.CancellationPending = False
                client = listener.AcceptTcpClient
                'Do something with your client.
                client.Close()
            End While
        End Sub

    End Class

This is how I implemented TCPListener. I have about 0.1% usage on my FX-8350. I can't say for certain what it was like on my Athlon II X2 but it couldn't have been more than a few percent. The GUI won't freeze, and you shouldn't have any real CPU usage.

Of course, my actual implementation is in a couple different classes. This is a simple example of the base.

Upvotes: 0

Jon Skeet
Jon Skeet

Reputation: 1500675

Any time you find yourself reaching for Application.DoEvents, you should try to reconsider - it's generally a workaround. At least this time you already know you're in a bad situation :)

If you're happy to do everything synchronously, I would start up a new thread and then call TcpListener.AcceptTcpClient in that. (You could call TcpListener.AcceptSocket if you really want the socket, but TcpClient is usually a simpler way to go.) That call will block until there's a client ready anyway, so you don't need to loop round checking the Pending property.

So you'll have your UI thread ready to receive UI events, and one thread waiting for inbound requests.

Now, you could use the asynchronous API instead - especially if you're using VB11, with Async and Await. You could use:

Dim client As TcpClient = Await listener.AcceptTcpClientAsync();

... in the UI thread. That won't block the UI thread, but will asynchronously start accepting an incoming connection. When the connection is made, the rest of your async method will continue. You don't need the extra thread. You can potentially do all your work on the UI thread, using asynchrony to avoid blocking. That will make it easier to interact with the UI, but it takes some getting used to.

If you're new to both asynchrony and networking, I'd probably start with the synchronous version... there'll be less to get your head round. Then if you're feeling adventurous later on, you can convert everything to the asynchronous approach.

Upvotes: 2

Related Questions