How to abort thread that use AcceptTcpClient() inside? - c#

AcceptTcpClient() prevents app from exit after I called thrd.Abort().
How to exit application when in listening?

You should be able to interrupt the call to AcceptTcpClient() by closing the TcpListener (this will result in an exception being thrown by the blocking AcceptTcpClient(). You should not be aborting the thread, which is generally a very bad idea in all but a few very specific circumstances.
Here's a brief example:
class Program
{
static void Main(string[] args)
{
var listener = new TcpListener(IPAddress.Any, 12343);
var thread = new Thread(() => AsyncAccept(listener));
thread.Start();
Console.WriteLine("Press enter to stop...");
Console.ReadLine();
Console.WriteLine("Stopping listener...");
listener.Stop();
thread.Join();
}
private static void AsyncAccept(TcpListener listener)
{
listener.Start();
Console.WriteLine("Started listener");
try
{
while (true)
{
using (var client = listener.AcceptTcpClient())
{
Console.WriteLine("Accepted client: {0}", client.Client.RemoteEndPoint);
}
}
}
catch(Exception e)
{
Console.WriteLine(e);
}
Console.WriteLine("Listener done");
}
}
The code above starts a listener on a separate thread, pressing Enter on the console window will stop the listener, wait for the listener thread to complete, then the application will exit normally, no thread aborts required!

You could:
Use BeginAcceptTcpClient() and End.. instead:
See:https://msdn.microsoft.com/en-us/library/system.net.sockets.tcplistener.beginaccepttcpclient(v=vs.110).aspx
Or your could:
Create a TcpClient and send your listener message:
therefore (I guess you have a loop in your thread):
break the loop wherein the listener.AcceptTcpClient() is running.
(i.e. CancelAsync()) from outside and
Loop While (!Tread.CancellationPending);
Create a TcpClient and send your listener a message (and discard data);
TcpClient see: https://msdn.microsoft.com/en-us/library/system.net.sockets.tcpclient(v=vs.110).aspx
Now your thread can go on with:
client.close() and listener.stop()

Related

Loop won't stop with Thread and CancellationToken

I'm working with a Windows socket application using async callbacks. If I use Thread to start _StartListening, when I call StopListening, the loop still stops at allDone.WaitOne(). But the Task version will be OK.
What's the difference?
My code is a modified version of this
The original version with ManualResetEvent has a race condition mentioned by felix-b. I changed it to SemaphoreSlim but the problem is still there.
I tried in debug mode and it seems that the break point never be hit at if (cancelToken.IsCancellationRequested) after I call StopListening even I don't start the client.
Sorry. I found that I accidentally started two socket servers. That's the problem.
class WinSocketServer:IDisposable
{
public SemaphoreSlim semaphore = new SemaphoreSlim(0);
private CancellationTokenSource cancelSource = new CancellationTokenSource();
public void AcceptCallback(IAsyncResult ar)
{
semaphore.Release();
//Do something
}
private void _StartListening(CancellationToken cancelToken)
{
try
{
while (true)
{
if (cancelToken.IsCancellationRequested)
break;
Console.WriteLine("Waiting for a connection...");
listener.BeginAccept(new AsyncCallback(AcceptCallback),listener);
semaphore.Wait();
}
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
Console.WriteLine("Complete");
}
public void StartListening()
{
Task.Run(() => _StartListening(cancelSource.Token));//OK
var t = new Thread(() => _StartListening(cancelSource.Token));
t.Start();//Can't be stopped by calling StopListening
}
public void StopListening()
{
listener.Close();
cancelSource.Cancel();
semaphore.Release();
}
public void Dispose()
{
StopListening();
cancelSource.Dispose();
semaphore.Dispose();
}
}
Your code has a race condition that can lead to deadlock (sometimes). Let's name the threads "listener" (one that runs _StartListening) and "control" (one that runs StopListening):
Listener thread: if (cancelToken.IsCancellationRequested) -> false
Control thread: cancelSource.Cancel()
Control thread: allDone.Set()
Listener thread: allDone.Reset() -> accidentally resets the stop request!
Listener thread: listener.BeginAccept(...)
Control thread: stopListening() exits, while the listener continues to work!
Listener thread: allDone.WaitOne() -> deadlock! no one will do allDone.Set().
The problem is in how you use the allDone event, it should be the other way around: _StartListening should do allDone.Set() just before it exits for whatever reason, whereas StopListening should do allDone.WaitOne():
class WinSocketServer:IDisposable
{
// I guess this was in your code, necessary to show proper stopping
private Socket listener = new Socket(......);
public ManualResetEvent allDone = new ManualResetEvent(false);
private CancellationTokenSource cancelSource = new CancellationTokenSource();
private void _StartListening(CancellationToken cancelToken)
{
try
{
listener.Listen(...); // I guess
allDone.Reset(); // reset once before starting the loop
while (!cancelToken.IsCancellationRequested)
{
Console.WriteLine("Waiting for a connection...");
listener.BeginAccept(new AsyncCallback(AcceptCallback),listener);
}
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
allDone.Set(); // notify that the listener is exiting
Console.WriteLine("Complete");
}
public void StartListening()
{
Task.Run(() => _StartListening(cancelSource.Token));
}
public void StopListening()
{
// notify the listener it should exit
cancelSource.Cancel();
// cancel possibly pending BeginAccept
listener.Close();
// wait until the listener notifies that it's actually exiting
allDone.WaitOne();
}
public void Dispose()
{
StopListening();
cancelSource.Dispose();
allDone.Dispose();
}
}
UPDATE
It worth noting that listener.BeginAccept won't return until there is a new client connection. When stopping the listener, it is necessary to close the socket (listener.Close()) to force BeginAccept to exit.
The difference in Thread/Task behavior is really weird, it probably can originate from the Task thread being a background thread, while the regular thread being a foreground one.

Understanding async behaviour of C# console TCP server

I want to create a simple TCP server in .NET Core 2.0 using asynchrony (because from what I understand, it's more reasonable than spawning threads) with the async/await approach (because I believe it's more up-to-date than the one with IAsyncResult and *Begin/*End methods).
I've written this small server that accepts new connections from clients and then begins to send them 100 messages (with a 1s delay between them).
The main question is:
If I'm not spawning new threads, then how the server continues to send delayed messages to several clients, when in fact it's "waiting for connection"? Are there any hidden low-level signals/events involved, or are there really just new threads?
The second question is:
If I'm not using this brand new async Main syntax sugar and I'm not "awaiting" the async task of sending the messages -- am I using the asynchrony correctly?
class Program
{
public static void Main(string[] args)
{
StartServer();
}
public static void StartServer()
{
IPAddress localhost = IPAddress.Parse("127.0.0.1");
TcpListener listener = new TcpListener(localhost, 5567);
Console.WriteLine($"Starting listening on {listener.Server.LocalEndPoint}");
listener.Start();
while (true)
{
Console.WriteLine("Waiting for connection...");
var client = listener.AcceptTcpClient(); // synchronous
Console.WriteLine($"Connected with {client.Client.RemoteEndPoint}!");
Console.WriteLine("Starting sending messages...");
SendHundredMessages(client); // not awaited -- StartServer is not async
}
}
public static async Task SendHundredMessages(TcpClient client)
{
var stream = client.GetStream();
for (int i=0; i<100; i++)
{
var msg = Encoding.UTF8.GetBytes($"Message no #{i}\n");
await stream.WriteAsync(msg, 0, msg.Length); // returning back to caller?
await Task.Delay(1000); // and what about here?
}
client.Close();
}
}
What is the difference between the original code and the version below? What difference does async Main make?
class Program
{
public static async Task Main(string[] args)
{
await StartServer();
}
public static async Task StartServer()
{
IPAddress localhost = IPAddress.Parse("127.0.0.1");
TcpListener listener = new TcpListener(localhost, 5567);
Console.WriteLine($"Starting listening on {listener.Server.LocalEndPoint}");
listener.Start();
while (true)
{
Console.WriteLine("Waiting for connection...");
var client = await listener.AcceptTcpClientAsync(); // does it make any difference when done asynchronously?
Console.WriteLine($"Connected with {client.Client.RemoteEndPoint}!");
Console.WriteLine("Starting sending messages...");
SendHundredMessages(client); // cannot await here, because it blocks next connections
}
}
public static async Task SendHundredMessages(TcpClient client)
{
var stream = client.GetStream();
for (int i=0; i<100; i++)
{
var msg = Encoding.UTF8.GetBytes($"Message no #{i}\n");
var result = stream.WriteAsync(msg, 0, msg.Length);
await Task.Delay(1000);
await result;
}
client.Close();
}
}
The answer to the main question:
In the background, as a rule, objects work with some api(winapi for windows). These api can implement asynchrony differently. For example, events(winapi events) or callbacks. So the answer is yes - there are hidden signals or threads. For example, you can see the Ping class. Ping.InternalSend using ThreadPool.RegisterWaitForSingleObject for the task of asynchrony.
The answer about async Main:
In your first code because StartServer is not async the Main method will not get back control until your "accept" cycle ends.
In your second code, the Main method will get back control then listener.AcceptTcpClientAsync invoked. But because you using await StartServer(); the Main method will be wait until StartServer ends.
Some code for to explain:
using System;
using System.Threading;
using System.Threading.Tasks;
namespace TestConsole
{
class Program
{
static void Main(string[] args)
{
// not await for exploration
var task = StartServer();
Console.WriteLine("Main StartServer finished");
task.Wait();
Console.WriteLine("task.Wait() finished");
Console.ReadKey();
}
static async Task StartServer()
{
Console.WriteLine("StartServer enter");
for(int i = 0; i < 3; i++) {
await Task.Delay(1000); // listener.AcceptTcpClientAsync simulation
SendHundredMessages();
}
Console.WriteLine("StartServer exit");
}
static async Task SendHundredMessages()
{
Console.WriteLine("SendHundredMessages enter");
await Task.Run(() => {
Thread.Sleep(2000);
});
Console.WriteLine("SendHundredMessages exit");
}
}
}
This code generate this output:
StartServer enter
Main StartServer finished
SendHundredMessages enter
SendHundredMessages enter
SendHundredMessages exit
SendHundredMessages enter
StartServer exit
task.Wait() finished
SendHundredMessages exit
SendHundredMessages exit
As you can see, the Main method continued execution right after first Task.Delay.
A warning:
You do not wait end of SendHundredMessages, and this is very bad. In example output you can see that "SendHundredMessages ending" after "task.Wait() finished". In example application of course it not danger, but in real project you can get big problem.

Executing an asynchronous socket on a background thread

I have been having playing with implementing some socket code to see if it fits my needs and so use the sample code #spender kindly added to this question.
If I run this on the main thread it works as expected but when I invoke it on a background thread it never gets awoken from its sleep when a client attempts to connect, my thread spawn is as below:
_Thread = new Thread(new ThreadStart(StartListening));
_Thread.Name = "ThreadForSocket";
_Thread.IsBackground = true;
_Thread.Start();
private void StartListening()
{
new AsyncSocketListener().StartListening(InitializeEndPoint());
}
public class AsyncSocketListener : IDisposable
{
public void StartListening(IPEndPoint endPoint)
{
try
{
var socket = new Socket(endPoint.Address.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
socket.Bind(endPoint);
socket.Listen(10);
while (true)
{
string info = string.Format("{0} Waiting for a connection...", DateTime.Now.ToString("HH:mm.ss"));
Controller.StatusSignal.Reset();
Console.WriteLine(info);
Debug.WriteLine(info);
socket.BeginAccept(new AsyncCallback(SocketListener.AcceptCallback), socket);
Controller.StatusSignal.WaitOne();
}
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
Console.WriteLine("Closing the listener...");
}
The thread is still present in the Threads Window and is in the expected state so I'm at a loss as to why it refuses to wake up on client connection.
Should that be possible? I read the socket msdn page and it appears to suggest it should be OK for a background thread.
(After too much hair-pulling and a process of elimination)
The code is fine, (Windows) Firewall had blocked the binary using the background thread (without notifying, despite its settings) but had allowed the non-threaded version thru, hence why I originally thought it was a code issue.
So, yes, the async pattern shown above is perfectly fine running on a background thread as shown, and of course its quite a nice way of using it as you are simply sleeping the bg thread and your main (eg. UI) thread can operate normally.

Stopping and restarting HttpListener?

I am working on an app that has an HttpListener. My goal is for the user to turn the listener off and on as they choose. I put the Listener in a new thread and I'm having a problem aborting that thread. I read somewhere that if you try to abort a thread that is in an unmanaged context, then as soon as it re-enters a managed context the ThreadAbortException will be fired. It appears that an HttpListener's GetContext() method is unmanaged because when I try to abort the thread nothing happens until I make a web request against my app. THEN the thread exits. The problem is when I attempt to kill the thread, I may start up the thread again later on the same port and an HttpListenerException goes off saying that the prefix is already registered.
How can I kill a cross thread HttpListener? Is there a managed alternative to GetContext() that will allow the thread to abort? Can I abort the thread in a way that unmanaged code will halt?
What about something like:
public class XListener
{
HttpListener listener;
public XListener(string prefix)
{
listener = new HttpListener();
listener.Prefixes.Add(prefix);
}
public void StartListen()
{
if (!listener.IsListening)
{
listener.Start();
Task.Factory.StartNew(async () =>
{
while (true) await Listen(listener);
}, TaskCreationOptions.LongRunning);
Console.WriteLine("Listener started");
}
}
public void StopListen()
{
if (listener.IsListening)
{
listener.Stop();
Console.WriteLine("Listener stopped");
}
}
private async Task Listen(HttpListener l)
{
try
{
var ctx = await l.GetContextAsync();
var text = "Hello World";
var buffer = Encoding.UTF8.GetBytes(text);
using (var response = ctx.Response)
{
ctx.Response.ContentLength64 = buffer.Length;
ctx.Response.OutputStream.Write(buffer, 0, buffer.Length);
}
}
catch (HttpListenerException)
{
Console.WriteLine("screw you guys, I'm going home!");
}
}
}
Usage:
var x = new XListener("http://locahost:8080");
x.StartListen();
Thread.Sleep(500); // test purpose only
x.StopListen();
Thread.Sleep(500); // test purpose only
x.StartListen();
/* OUTPUT:
=> Listener started
=> Listener stopped
=> screw you guys, I'm going home!
=> Listener started */
You need to signal the thread to call HttpListener.Stop() and wait for the thread to finish by calling Thread.Join()
All you need to do is call stop on the listener. Since your listener thread is blocked on GetContext you will need to do this on another thread. IIRC this will cause GetContext to throw, so you will want to handle that exception and clean up. Calling Thread.Abort should be your last resort and wont cause the listener to stop listening until it is garbage collected anyway.
using System;
using System.Net;
using System.Text;
class Server
{
HttpListener listener = new HttpListener();
public Server(string url)
{
listener.Prefixes.Add(url);
}
void Callback(IAsyncResult result)
{
HttpListenerContext context = listener.EndGetContext(result);
byte[] buffer = Encoding.UTF8.GetBytes("Hello world!");
context.Response.ContentLength64 = buffer.Length;
context.Response.OutputStream.Write(buffer, 0, buffer.Length);
context.Response.OutputStream.Close();
listener.BeginGetContext(new AsyncCallback(Callback), listener);
}
public void Start()
{
listener.Start();
listener.BeginGetContext(new AsyncCallback(Callback), listener);
}
public void Stop()
{
listener.Stop();
}
public void Close()
{
listener.Close();
}
}

Must i abort this thread? Waiting for namedpipes. How do i do this properly?

I have another question about this same code and keeping the pipe open after the client closes it
But here i have a problem gracefully terminating my app. My main code is below. There are 2 problems. 1) I am using Thread.Abort and 2) This application doesnt actually end. I can set a breakpoint and see abort is called and step to the ending brace but the IDE is still in debug mode and the process is still alive (in process manager). How do i properly terminate this?
[STAThread]
static void Main(string[] args)
{
Thread t;
t = new Thread(new ThreadStart(ThreadStartServer));
bool hasInstance = true;
try
{
pipeStream = new NamedPipeServerStream(pipename);
hasInstance = false;
pipeStream.Close();
t.Start();
pipeStream.Dispose();
}
catch (System.IO.IOException)
{
hasInstance = true;
}
if (hasInstance)
{
clientPipeMessage(args[1]);
return;
}
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
t.Abort();
}
static public void ThreadStartServer()
{
while (true)
{
using (NamedPipeServerStream pipeStream = new NamedPipeServerStream(pipename))
{
Console.WriteLine("[Server] Pipe created {0}", pipeStream.GetHashCode());
// Wait for a connection
pipeStream.WaitForConnection();
Console.WriteLine("[Server] Pipe connection established");
using (StreamReader sr = new StreamReader(pipeStream))
{
string temp;
while ((temp = sr.ReadLine()) != null)
{
Console.WriteLine("{0}: {1}", DateTime.Now, temp);
}
}
}
}
Console.WriteLine("Connection lost");
}
About Thread.Abort from MS documentation ... "Calling this method usually terminates the thread."
Furthermore "The thread is not guaranteed to abort immediately, or at all."
I suspect the WaitForConnection is blocking it from receiving the thread abort. Generally speaking, thread abort is considered Evil as who knows what state you could leave things in, etc. See here for some more help...http://www.interact-sw.co.uk/iangblog/2004/11/12/cancellation
As you suggest ... don't use Thread.Abort. Unless you have a very compelling reason why no other option will work it is a bad idea.
The problem is the blocking call to ReadLine ... so instead use StreamReader.Peek/Read to pull data from the named pipe. This will allow you to check a flag in the loop so that you can exit.
For a more complex solution you could use asynchronous I/O ... see this question for some pointers.
You need to "return" from your ThreadStartServer method when it has completed its work. If you combine this with a Join() in the Main method, the worker thread will finish gracefully. Additionally make it a BackGround thread. Here is an example (without the PipeStream):
class Prog
{
static void Main(string[] args)
{
Thread t;
t = new Thread(new ThreadStart(ThreadStartServer));
t.IsBackground = true;
try
{
t.Start();
// time consuming work here
}
catch (System.IO.IOException)
{
// from your example
}
t.Join();
}
static public void ThreadStartServer()
{
while (true)
{
int counter=0;
while (++counter < 10)
{
Console.WriteLine("working.");
// do time consuming things
Thread.Sleep(500);
}
return;
}
}
}

Categories