我的理解是Thread.Abort应该在被阻塞的线程上引发ThreadAbortException,但是在处理TcpListener.AcceptSocket
时似乎不是这种情况。以下是该问题的最基本说明:
class Program
{
static void Main(string[] args)
{
Thread thread = new Thread(Listen);
thread.Start();
Thread.Sleep(1000); // give it a second to get going
Console.WriteLine("Aborting listener thread");
thread.Abort();
thread.Join();
Console.WriteLine("Listener thread finished press <enter> to end app.");
Console.ReadLine();
}
static void Listen()
{
try
{
Console.WriteLine("Starting to listen");
TcpListener listener = new TcpListener(IPAddress.Any, 4070);
listener.Start();
Socket socket = listener.AcceptSocket();
Console.WriteLine("Connected!");
return;
}
catch (ThreadAbortException exception)
{
Console.WriteLine("Abort requested");
}
}
}
thread.Abort()
调用应停止AcceptSocket
并执行ThreadAbortException
处理程序。但这并没有发生。
为ListenAsync替换AcceptSocket
的Listen包装器,而不是调用BeginAcceptSocket
:
static void ListenAsync()
{
try
{
ManualResetEvent clientConnected = new ManualResetEvent(false);
Console.WriteLine("Starting to listen");
TcpListener listener = new TcpListener(IPAddress.Any, 4070);
listener.Start();
clientConnected.Reset();
var iasyncResult = listener.BeginAcceptSocket((ar) =>
{
Socket socket = listener.EndAcceptSocket(ar);
Console.WriteLine("Connected!");
clientConnected.Set();
}, null);
clientConnected.WaitOne();
return;
}
catch (ThreadAbortException exception)
{
Console.WriteLine("Abort requested");
}
}
在这种情况下,它“似乎”工作正常。线程正在执行WaitOne时捕获ThreadAbortException。然而,调用BeginAcceptSocket创建的线程仍在运行并且能够接受套接字(我通过使用Telnet打开该端口来验证这一点)
最后,我添加Listener.Stop
作为TheadAbortException
处理程序的一部分,并尝试捕获EndAcceptSocket调用(因为套接字由Stop处理)
这是启动和停止侦听套接字连接的最佳方法吗?
答案 0 :(得分:7)
Thread.Abort
不会中止正在侦听套接字的线程的原因是因为该线程在listen()
内核调用内被阻塞(道德等同)。当CLR实际执行时,ThreadAbortException
只能由CLR引发,并且在调用listen
线程期间实际上卡在非托管系统调用中。一旦对listen
的调用返回并在CLR内部恢复执行,就可以继续线程中止。
我建议不要使用Thread.Abort()
。如果您决定采用该路线,则可以使用与第二个示例中的技术类似的技术。但是,如果要关闭线程侦听器,最好使用其他方法并调用Listener.Stop()
。