How to do Async TCP Listener?

  • Thread starter Thread starter Terry Olsen
  • Start date Start date
T

Terry Olsen

I've tried the following code straight out of MSDN. But my app still blocks
while listening. Isn't this code supposed to keep the UI responsive while
listening? Or maybe I'm not doing it right.... any help is begged for ;-)

Public Class Listener

Public Event Connected(ByVal client As TcpClient)
Public ClientConnected As New ManualResetEvent(False)

Public Sub DoBeginAcceptTcpClient()
Dim myListener As New TcpListener(IPAddress.Parse("127.0.0.1"), 23)
myListener.Start()
ClientConnected.Reset()
myListener.BeginAcceptTcpClient(New AsyncCallback(AddressOf
DoAcceptTcpClientCallback), myListener)
ClientConnected.WaitOne()
End Sub

Public Sub DoAcceptTcpClientCallback(ByVal ar As IAsyncResult)
Dim myListener As TcpListener = CType(ar.AsyncState, TcpListener)
Dim client As TcpClient = myListener.EndAcceptTcpClient(ar)
RaiseEvent Connected(client)
ClientConnected.Set()
End Sub

End Class
 
I suspect your listening socket is a "blocking" socket (not always obvious)
that the OS is running in an internal thread for you. If so, your client
socket that is created during the accept function will also be blocking. To
fix this, issue a socket ioctl call to the new client socket immediately
after the accept to switch it from blocking to non-blocking.

Mike Ober.
 
How do I create a listener that doesn't block? I want to be able to stop
the listner from my app, but the app is locked up while it's listening.
 
You need to derive a new object from your listening socket object. There is
an overridable "OnAccept" event in VB6's WINSOCK.ocs and in the MFC
CAsyncSocket class so there should be one in .Net as well.

Mike.
 
I've tried the following code straight out of MSDN. But my app still blocks
while listening. Isn't this code supposed to keep the UI responsive while
listening? Or maybe I'm not doing it right.... any help is begged for ;-)

Public Class Listener

Public Event Connected(ByVal client As TcpClient)
Public ClientConnected As New ManualResetEvent(False)

Public Sub DoBeginAcceptTcpClient()
Dim myListener As New TcpListener(IPAddress.Parse("127.0.0.1"), 23)
myListener.Start()
ClientConnected.Reset()
myListener.BeginAcceptTcpClient(New AsyncCallback(AddressOf
DoAcceptTcpClientCallback), myListener)
ClientConnected.WaitOne()
End Sub

Public Sub DoAcceptTcpClientCallback(ByVal ar As IAsyncResult)
Dim myListener As TcpListener = CType(ar.AsyncState, TcpListener)
Dim client As TcpClient = myListener.EndAcceptTcpClient(ar)
RaiseEvent Connected(client)
ClientConnected.Set()
End Sub

End Class

Unless your DoBeginAcceptTcpClient () method is on a separate thread,
then it will block - but not at the BeginAcceptTcpClient, but at the
ClientConnected.WaitOne ().

Normally, I would start listening on a separate thread, and do something
like:

Do While Until Terminate
ClientConnected.Reset()
MyListener.BeginAccept......
ClientConnected.WaiteOne ()
Loop

This way, you can handle multiple clients, and you won't block the main
thead. When you need to kill the thread, just close the listener...

Don't ask me any specifics about TcpListener/Client - I never use them.
I always use the Socket class in System.Net.Sockets :)
 
Speaking of the ManualResetEvent...what's it used for? I commented out all
the "ClientConnected.x" code and the listener still worked fine...without
blocking at all...
 
It was the "ClientConnected.WaitOne()" that caused you to block.

The ManualResetEvent is an object that lets a thread sleep until the "Set"
is called. The problem you hit is that you called WaitOne() from your UI
thread. You should have called that from a worker (listener) thread, like in
Tom's example.

Regards,
Tom C
 
Can you tell me why I would need a ManualResetEvent at all (in this
particular situation)? I removed it and now everything seems to work fine.
 
Terry,

In this particular situation (because you are using a callback and don't
need/want to "wait" for a connection, you do not need to use one.

(Be careful in your callback though, because it is called from a non-GUI
thread and you must use Invoke() to update GUI components),

Regards,
Tom C.
 
Back
Top