C# 停止并重新启动HttpListener?

C# 停止并重新启动HttpListener?,c#,multithreading,httplistener,C#,Multithreading,Httplistener,我正在开发一个具有HttpListener的应用程序。我的目标是让用户根据自己的选择关闭和打开侦听器。我将侦听器放入一个新线程,但中止该线程时遇到问题。我在某个地方读到,如果您试图中止非托管上下文中的线程,那么一旦它重新进入托管上下文,就会触发ThreadAbortException。HttpListener的GetContext()方法似乎是非托管的,因为当我尝试中止线程时,在我对我的应用程序发出web请求之前,不会发生任何事情。然后线程退出。问题是,当我试图终止线程时,我可能稍后在同一端口上

我正在开发一个具有
HttpListener
的应用程序。我的目标是让用户根据自己的选择关闭和打开侦听器。我将侦听器放入一个新线程,但中止该线程时遇到问题。我在某个地方读到,如果您试图中止非托管上下文中的线程,那么一旦它重新进入托管上下文,就会触发
ThreadAbortException
。HttpListener的
GetContext()
方法似乎是非托管的,因为当我尝试中止线程时,在我对我的应用程序发出web请求之前,不会发生任何事情。然后线程退出。问题是,当我试图终止线程时,我可能稍后在同一端口上再次启动该线程,然后会出现
HttpListenerException
提示前缀已注册


如何杀死跨线程HttpListener?除了
GetContext()
之外,还有允许线程中止的托管替代方案吗?我是否可以以非托管代码将停止的方式中止线程?

您需要向线程发出信号,以调用HttpListener.Stop(),并通过调用thread.Join()等待线程结束。

您只需在侦听器上调用Stop即可。由于侦听器线程在
GetContext
上被阻塞,因此需要在另一个线程上执行此操作。IIRC这将导致抛出
GetContext
,因此您需要处理该异常并进行清理。调用
Thread.Abort
应该是您的最后手段,并且不会导致侦听器停止侦听,直到它被垃圾回收。

类似于:

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

使用全局变量。我假设您的侦听线程正在检查传入的连接,因此您可以执行以下操作:while(!shutdown){//listen};listener.Stop();在信令线程中,您将执行以下操作:shutdown=true;listingThread.Join();matt dot net:问题是线程正在等待HttpListener.GetContextAsync(),因此无法定期检查是否请求停止。可惜没有重载
GetContextAsync(CancellationToken)
。使线程停止侦听的唯一方法是调用
HttpListener.stop()
GetContextAsync()不会阻塞,除非您使用的是wait。您需要处理(a)接收和处理传入连接的同步性。应该允许此循环检查关机,然后清理生成的异步任务。从GetContextAsync()返回的任务是您需要启动的地方,或者可能使用Begin/End GetContextAsync的原始IAsyncResult模式。如果可能,请使用BeginGetContext()和EndGetContext()实现您的HttpListener。请发布一些代码,说明如何启动线程,等等您可能会在某个地方潜入一个
CancellationToken
,每当用户“关闭”侦听器时,您都可以调用
CancellationToken
上的
Cancel
方法,该方法有一个延续,即它应该调用
HttpListener.Stop()
。您应该解释这是如何工作的,以及具体做什么。这将改善这个答案
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();
        }
   }