tcpLisetener + Thread problem

  • Thread starter Thread starter C# Learner
  • Start date Start date
C

C# Learner

Socket socket = listener.AcceptSocket();
if ( IsStopped )
break;

Problem here is that if there's no client and no blocking timeout, the
server keeps listening for an indefinite amount of time. So is this really
a solution?

Also, since the thread isn't a background thread (Thread.IsBackground),
this application, as is, won't terminate on its own under certain
conditions.
 
Problem here is that if there's no client and no blocking timeout, the
server keeps listening for an indefinite amount of time. So is this really
a solution?

Also, since the thread isn't a background thread (Thread.IsBackground),
this application, as is, won't terminate on its own under certain
conditions.

Sorry -- I inadvertently skipped over TcpListener.Stop call.
 
Hello there,

Lets say I have something like this in my Mother Of All Threads:

Thread thread1 = new Thread(new ThreadStart(this.run));
thread1.Start();
//some unimportant code
thread1.Abort();
thread1.Join();

And in thread1 I have:

try {
tcpListener = new TcpListener(this.port);
tcpListener.Start();
tcpClient = tcpListener.AcceptTcpClient();
//more unimportant code
} catch (ThreadAbortException) {
tcpClient.Stop();
//not sure whether I need the line above, but that's not the problem
anyway
tcpListener.Stop();
}

What happens now is thread1 gets started, gets to the
"tcpListener.AcceptTcpClient()" call and waits for a client to connect.
In
the mean time Mother Of All Threads gets to the "thread1.Abort()" and
raises the ThreadAbortException... and nothing happens. tcpListener
still
hangs and waits for the connection, and blocks the ThreadAbortException
from occuring! Now, shouldn't that be impossible? I was taught to firmly
believe in the Almighty Exception... something's very wrong here...
would
somebody enlighten me, please! :-)

BTW, yes, I know, I could make a socket which will connect to the server
and unblock the Listener, but that's a dirty and ugly hack. There should
be some elegant solution for interupting tcpListener... shouldn't it?
 
The tcp listener calls accept on a socket object which in turn calls out to
a native method using P/Invoke.

I would imagine that the exception don't travel to the native method and
therefore the thread wont be aborted. I've experienced similar behaviour
with SqlDataAdapter.Fill but never found the solution..
 
I've dug around for a bit.

There's a stop method on the TcpListener class. The stop method closes and
throws away the underlying socket. Try calling Stop on the listener instead
of abort the thread.

Another way is to kill the thread is to use the API TerminateThread but that
is a potential catastrophy since you wouldn't know what resources the native
code has opened and won't have the chance to close or release.

The third solution is probably a total overkill, you could let the thread
run in a separate appdomain and unload the appdomin itself, this might
terminate the thread but you have no guarantee.
 
Nikola Skoric said:
Hello there,

Lets say I have something like this in my Mother Of All Threads:

Thread thread1 = new Thread(new ThreadStart(this.run));
thread1.Start();
//some unimportant code
thread1.Abort();
thread1.Join();

And in thread1 I have:

try {
tcpListener = new TcpListener(this.port);
tcpListener.Start();
tcpClient = tcpListener.AcceptTcpClient();
//more unimportant code
} catch (ThreadAbortException) {
tcpClient.Stop();
//not sure whether I need the line above, but that's not the problem
anyway
tcpListener.Stop();
}

What happens now is thread1 gets started, gets to the
"tcpListener.AcceptTcpClient()" call and waits for a client to connect.
In
the mean time Mother Of All Threads gets to the "thread1.Abort()" and
raises the ThreadAbortException... and nothing happens. tcpListener
still
hangs and waits for the connection, and blocks the ThreadAbortException
from occuring! Now, shouldn't that be impossible? I was taught to firmly
believe in the Almighty Exception... something's very wrong here...
would
somebody enlighten me, please! :-)

BTW, yes, I know, I could make a socket which will connect to the server
and unblock the Listener, but that's a dirty and ugly hack. There should
be some elegant solution for interupting tcpListener... shouldn't it?

I don't know why the ThreadAbortException doesn't work (though maybe it's
related to the problem discussed in
but the method I use to abort
the TcpListener is to call tcpListener.Stop() from the main thread (i.e.
from your Mother Of All Threads). This raises a SocketException in the
listening thread (your thread1). I'm not sure whether this is 100% safe,
since calling a method of the TcpListener from a different thread than the
one it was created on may lead to some nasty race condition - but AFAIK it's
never gone wrong in practice.

Chris Jobson
 
Dana Sun, 10 Oct 2004 18:56:55 +0200
Nikola Skoric ([email protected]) kaze...
Hello there,

Lets say I have something like this in my Mother Of All Threads: /snip
would
somebody enlighten me, please! :-)

Ahhhhhhhhhhhhhh! Found the soution (although I still lack the
explanation of Exception blocking "feature"). I just put this:

while (!tcpListener.Pending()) Thread.Sleep(500);

before this:

tcpClient = tcpListener.AcceptTcpClient();

Now the Exception is handled and everthing goes fine.
 
while (!tcpListener.Pending()) Thread.Sleep(500);

Hi Nikola. This is not a great solution for a couple reasons. One is that
clients will have to wait 0-500ms to connect, so your forcing an artificial
connect slowdown. Second, your introducing a spin for no reason. When not
clients connect, your spinning forever which wastes cpu time and on a laptop
or other small device would drain the battery as it would not allow cpu to
go into low power state. Below is simple server implementation that allows
you to block until connect and also allows you to shutdown. You still throw
a socket exception when stopping the listener as it is in blocking mode, but
that is ok as we expect it and catch it before shutting down.

/// <summary>
/// Server listens and writes files to disk.
/// </summary>
public sealed class SimpleServer
{

private readonly Thread thread;
private readonly TcpListener listener;
private bool stopped = true;
private readonly object syncRoot;

public SimpleServer(IPAddress listenIP, int port)
{
if ( listenIP == null )
throw new ArgumentNullException();
syncRoot = new object();
listener = new TcpListener(listenIP, port);
thread = new Thread(new ThreadStart(ServerStart));
thread.Name = "Listener";
}

public bool IsStopped
{
get
{
lock(syncRoot)
{
return stopped;
}
}
}

public bool IsStarted
{
get
{
lock(syncRoot)
{
return ! stopped;
}
}
}

public void Start()
{
lock(syncRoot)
{
if ( stopped )
{
stopped = false;
thread.Start();
}
}
}

public void Stop()
{
lock(syncRoot)
{
if ( stopped )
return;
stopped = true;
listener.Stop();
}
}

private void ServerStart()
{
try
{
listener.Start();
Console.WriteLine("Listing on: "+listener.LocalEndpoint.ToString());
while( IsStarted )
{
// Wait for a client to connect.
Console.WriteLine("Waiting for a client to connect.");
Socket socket = listener.AcceptSocket();
if ( IsStopped )
break;
Console.WriteLine("Client Connected: " +
socket.RemoteEndPoint.ToString());

// Create and start client worker.
ClientWorker cw = new ClientWorker(socket);
cw.Start(); // Starts the worker which also starts it's thread.
}
}
catch(SocketException se)
{
// Calling listen.Stop() while Listening will throw
// "A blocking operation was interrupted by a call to
WSACancelBlockingCall".
Console.WriteLine("Server Socket Exception: " + se.Message);
}
catch(Exception ex)
{
Console.WriteLine("Server Exception: " + ex.Message);
}
finally
{
try
{
Stop();
Console.WriteLine("Server Stopped.");
}
catch
{
}
}
}
}
 
Dana Sun, 10 Oct 2004 19:43:58 -0400
William Stacey [MVP] ([email protected]) kaze...
Hi Nikola. This is not a great solution for a couple reasons. One is that
clients will have to wait 0-500ms to connect, so your forcing an artificial
connect slowdown. Second, your introducing a spin for no reason. When not
clients connect, your spinning forever which wastes cpu time and on a laptop
or other small device would drain the battery as it would not allow cpu to
go into low power state. Below is simple server implementation that allows
you to block until connect and also allows you to shutdown. You still throw
a socket exception when stopping the listener as it is in blocking mode, but
that is ok as we expect it and catch it before shutting down.

Thank you for explanation. It is most kind of you. I read this code and
it introduced a number of nice tricks I'll use. Somehow I thought I
shouldn't access objects instanced inside of some other thread... but I
don't remember anyone mentioning that explicitly... just my imagination
then :-)
public bool IsStopped
{
get
{
lock(syncRoot)
{
return stopped;
}
}
}

Say, why not "lock(stopped)"? Why do you need syncRoot?
public sealed class SimpleServer

And, why sealing the class? Is it you just have a practise of sealing
everthing you can (now, why would you do that?) or do you have a reason
you sealed this one?

Thank you again, you gave me some nice ideas.
 
Nikola Skoric said:
Thank you for explanation. It is most kind of you. I read this code and
it introduced a number of nice tricks I'll use. Somehow I thought I
shouldn't access objects instanced inside of some other thread... but I
don't remember anyone mentioning that explicitly... just my imagination
then :-)


Say, why not "lock(stopped)"? Why do you need syncRoot?

Because stopped is a boolean. Value types don't have associated
monitors.
And, why sealing the class? Is it you just have a practise of sealing
everthing you can (now, why would you do that?) or do you have a reason
you sealed this one?

Sealing classes that aren't specifically designed to be derived from is
good practice, IMO.
 
Back
Top