3

我正在开发一个具有HttpListener. 我的目标是让用户根据自己的选择关闭和打开监听器。我将侦听器放在一个新线程中,但在中止该线程时遇到问题。我在某处读到,如果您尝试中止处于非托管上下文中的线程,那么一旦它重新进入托管上下文,ThreadAbortException就会被触发。似乎 HttpListener 的GetContext()方法是非托管的,因为当我尝试中止线程时,除非我对我的应用程序发出 Web 请求,否则什么都不会发生。然后线程退出。问题是当我试图杀死线程时,我可能稍后会在同一个端口上再次启动线程,并且HttpListenerException会发出一个说前缀已经注册的消息。

如何杀死跨线程 HttpListener?是否有一个托管的替代方案GetContext()可以让线程中止?我可以以非托管代码停止的方式中止线程吗?

4

4 回答 4

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 */
于 2013-06-05T21:00:28.527 回答
1

您需要通知线程调用 HttpListener.Stop() 并通过调用 Thread.Join() 等待线程完成

于 2013-06-05T17:39:46.980 回答
0

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

于 2013-06-05T18:06:46.260 回答
0
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();
        }
   }
于 2020-11-02T19:21:12.440 回答