Reputation: 2220
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
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
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