How to do Async TCP Listener?

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
 
M

Michael D. Ober

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.
 
T

Terry Olsen

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.
 
M

Michael D. Ober

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.
 
T

Tom Shelton

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 :)
 
T

Terry Olsen

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...
 
T

tcarvin

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
 
T

Terry Olsen

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.
 
T

tcarvin

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.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top