2013-06-05 175 views
1

我正在研究一个具有HttpListener的应用程序。我的目标是让用户按照自己的选择开启和关闭收听者。我把Listener放在一个新的线程中,我遇到了一个中止该线程的问题。我在某处读到,如果您尝试中止处于非托管环境中的线程,那么只要它重新进入托管环境,将会触发ThreadAbortException。看起来,HttpListener的方法是非托管的,因为当我尝试中止线程时,什么也没有发生,直到我对我的应用程序发出Web请求。然后线程退出。问题是当我试图杀死线程时,我可能稍后在相同的端口上再次启动线程,并且HttpListenerException熄灭,表示该前缀已经注册。停止并重新启动HttpListener?

如何杀死一个交叉线程HttpListener?是否有一个可以替代GetContext()的替代方法,允许线程中止?我能否以非托管代码将停止的方式中止线程?

+1

如果可能的话,实现你的HttpListener使用BeginGetContext()和EndGetContext() – wgraham

+0

能否请您发布一些代码,显示了如何你开始线程等? - 你可以在某处取消'CancellationToken',并且每当用户“关闭”监听器,你可以调用'CancellationToken'上的'Cancel'方法 - 它有一个延续,说它应该调用'HttpListener.Stop ()'。 – ebb

回答

1

你需要信号线程调用HttpListener.Stop()和等待线程调用完成的Thread.join()

+0

那么,我如何发信号通知Stop()? –

+0

使用全局变量。我假设你的监听线程正在检查传入连接,所以你可能会这样做:while(!shutdown){// listen}; listener.Stop();并在信号线程中执行:shutdown = true; listeningThread.Join(); –

0

所有你需要做的是对听众通话停止。由于您的监听线程在GetContext上被阻止,您需要在另一个线程上执行此操作。 IIRC这将导致GetContext扔,所以你会想要处理这个异常和清理。拨打Thread.Abort应该是您的最后手段,并且不会导致听众停止收听,直到它无论如何都被垃圾收集。

2

什么是这样的:

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!"); 
     } 
    } 
} 

用法:

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 */