Vb.net 异步httpListener回调是在UI线程上启动的吗?

Vb.net 异步httpListener回调是在UI线程上启动的吗?,vb.net,asynchronous,httplistener,Vb.net,Asynchronous,Httplistener,我希望将httpListener构建成一个小型服务器应用程序。在阅读时,我遇到了下面的代码片段 这看起来很简单,很像。然而,当在一个虚拟项目中测试它时,我发现了一些让我困惑的事情,例如可以直接从回调子函数访问UI对象,我认为这应该会导致一个跨线程异常 为了澄清,我稍微修改了这段代码,使其在一个简单winforms项目的主窗体中运行 我似乎不完全理解代码,例如AsyncWaitHandle.WaitOne()对我来说是全新的 有人能简要地告诉我这个片段吗?非常感谢您的帮助。此代码片段如下所示: 它

我希望将httpListener构建成一个小型服务器应用程序。在阅读时,我遇到了下面的代码片段

这看起来很简单,很像。然而,当在一个虚拟项目中测试它时,我发现了一些让我困惑的事情,例如可以直接从回调子函数访问UI对象,我认为这应该会导致一个跨线程异常

为了澄清,我稍微修改了这段代码,使其在一个简单winforms项目的主窗体中运行

我似乎不完全理解代码,例如AsyncWaitHandle.WaitOne()对我来说是全新的


有人能简要地告诉我这个片段吗?非常感谢您的帮助。

此代码片段如下所示:

  • 它创建一个HttpListener并在uri处开始linsening
  • 它创建一些线程(System.Environment.ProcessorCount的数量*2)向侦听器发送异步请求,并尝试获取上下文
  • 然后该线程被调用SyncResult.AsyncWaitHandle.WaitOne()阻塞,关于AsyncWaitHandle.WaitOne请签出
  • 如果某个客户端请求进入,ListenerCallback()将被触发,并尝试将响应发送回客户端
  • 然后进入下一轮循环
  • 因为它调用SyncResult.AsyncWaitHandle.WaitOne()来阻止该线程,所以它将通过同步调用获得相同的结果

    在我看来,它只返回一个简单的OK响应,所以我们甚至不需要任何其他线程。我将很快向您展示代码(如果我们有繁重的操作,我的代码将不能很好地工作,请不要在表单应用程序中这样做。)

    static void Main(字符串[]args)
    {
    ServicePointManager.DefaultConnectionLimit=500;
    ServicePointManager.Expect100Continue=false;
    ServicePointManager.MaxServicePoints=500;
    HttpListener=新的HttpListener();
    listener.Prefixes.Add(“http://localhost:999/");
    listener.Start();
    BeginGetContext(ListenerCallBack,listener);
    Console.ReadLine();
    }
    私有静态void ListenerCallBack(IAsyncResult结果)
    {
    HttpListener HttpListener=(HttpListener)result.AsyncState;
    //调用EndGetContext以完成异步操作。
    HttpListenerContext=httpListener.EndGetContext(结果);
    HttpListenerRequest=context.request;
    //获取一个响应对象。
    HttpListenerResponse=context.response;
    //构建一个响应。
    string responseString=“你好,世界!”;
    byte[]buffer=System.Text.Encoding.UTF8.GetBytes(responseString);
    //获取响应流并将响应写入其中。
    response.ContentLength64=buffer.Length;
    System.IO.Stream输出=response.OutputStream;
    输出.写入(缓冲区,0,缓冲区.长度);
    //必须关闭输出流。
    output.Close();
    //我们调用BeginGetContext()为下一个客户机再次发送异步请求
    BeginGetContext(ListenerCallBack,httpListener);
    }
    
    在C#5和Net 4.5中,我们有同步方法,这将更容易:

    static void Main(string[] args)
        {
            ServicePointManager.DefaultConnectionLimit = 500;
            ServicePointManager.Expect100Continue = false;
            ServicePointManager.MaxServicePoints = 500;
    
            HttpListener listener = new HttpListener();
            listener.Prefixes.Add("http://localhost:999/");
            listener.Start();
    
            while (true)
            {
                var t = listener.GetContextAsync();
                HttpListenerContext context = t.Result;
                HttpListenerRequest request = context.Request;
                // Obtain a response object.
                HttpListenerResponse response = context.Response;
                // Construct a response. 
                string responseString = "<HTML><BODY> Hello world!</BODY></HTML>";
                byte[] buffer = System.Text.Encoding.UTF8.GetBytes(responseString);
                // Get a response stream and write the response to it.
                response.ContentLength64 = buffer.Length;
                System.IO.Stream output = response.OutputStream;
                output.Write(buffer, 0, buffer.Length);
                // You must close the output stream.
                output.Close();
            }
        }
    
    static void Main(字符串[]args)
    {
    ServicePointManager.DefaultConnectionLimit=500;
    ServicePointManager.Expect100Continue=false;
    ServicePointManager.MaxServicePoints=500;
    HttpListener=新的HttpListener();
    listener.Prefixes.Add(“http://localhost:999/");
    listener.Start();
    while(true)
    {
    var t=listener.GetContextAsync();
    HttpListenerContext=t.Result;
    HttpListenerRequest=context.request;
    //获取一个响应对象。
    HttpListenerResponse=context.response;
    //构建一个响应。
    string responseString=“你好,世界!”;
    byte[]buffer=System.Text.Encoding.UTF8.GetBytes(responseString);
    //获取响应流并将响应写入其中。
    response.ContentLength64=buffer.Length;
    System.IO.Stream输出=response.OutputStream;
    输出.写入(缓冲区,0,缓冲区.长度);
    //必须关闭输出流。
    output.Close();
    }
    }
    
    对于您关于UI的“跨线程异常”的另一个问题,您是对的,创建的新线程将具有SynchronizationContext.Current的空值,因为它是线程池线程,我们需要在窗体的SynchronizationContext中执行post()。以下是更多信息和。

    简单C#Web服务器,带有HttpListener(名称:服务器)、BackgroundWorker(名称:bw#服务器)、2个按钮(名称:btn#U开始和btn#U停止)和文本框(名称:tb#U日志):

        static void Main(string[] args)
        {
            ServicePointManager.DefaultConnectionLimit = 500;
            ServicePointManager.Expect100Continue = false;
            ServicePointManager.MaxServicePoints = 500;
    
            HttpListener listener = new HttpListener();
            listener.Prefixes.Add("http://localhost:999/");
            listener.Start();
            listener.BeginGetContext(ListenerCallBack, listener);
    
    
            Console.ReadLine();
        }
    
        private static void ListenerCallBack(IAsyncResult result)
        {
            HttpListener httpListener = (HttpListener) result.AsyncState;
            // Call EndGetContext to complete the asynchronous operation.
            HttpListenerContext context = httpListener.EndGetContext(result);
            HttpListenerRequest request = context.Request;
            // Obtain a response object.
            HttpListenerResponse response = context.Response;
            // Construct a response. 
            string responseString = "<HTML><BODY> Hello world!</BODY></HTML>";
            byte[] buffer = System.Text.Encoding.UTF8.GetBytes(responseString);
            // Get a response stream and write the response to it.
            response.ContentLength64 = buffer.Length;
            System.IO.Stream output = response.OutputStream;
            output.Write(buffer,0,buffer.Length);
            // You must close the output stream.
            output.Close();
    
    
            // we call BeginGetContext() to send async request again for next coming client
            httpListener.BeginGetContext(ListenerCallBack, httpListener);
        }
    
    static void Main(string[] args)
        {
            ServicePointManager.DefaultConnectionLimit = 500;
            ServicePointManager.Expect100Continue = false;
            ServicePointManager.MaxServicePoints = 500;
    
            HttpListener listener = new HttpListener();
            listener.Prefixes.Add("http://localhost:999/");
            listener.Start();
    
            while (true)
            {
                var t = listener.GetContextAsync();
                HttpListenerContext context = t.Result;
                HttpListenerRequest request = context.Request;
                // Obtain a response object.
                HttpListenerResponse response = context.Response;
                // Construct a response. 
                string responseString = "<HTML><BODY> Hello world!</BODY></HTML>";
                byte[] buffer = System.Text.Encoding.UTF8.GetBytes(responseString);
                // Get a response stream and write the response to it.
                response.ContentLength64 = buffer.Length;
                System.IO.Stream output = response.OutputStream;
                output.Write(buffer, 0, buffer.Length);
                // You must close the output stream.
                output.Close();
            }
        }
    
    public partial class Form1 : Form
    {
        HttpListener server;
        private void btn_start_Click(object sender, EventArgs e)
        {
            bw_server.RunWorkerAsync(@"http://+:80/");
        }
    
        private void bw_server_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
        {
            string prefix = e.Argument.ToString();
            bw_server.ReportProgress(0, "Starting server...");
            if (!bw_server.CancellationPending)
            {
                try
                {
                    start_server(prefix);
                }
                catch (Exception ex)
                {
                    bw_server.ReportProgress(0, ex.Message);
                    bw_server.CancelAsync();
                }
            }
            else
            {
                e.Cancel = true;
                return;
            }
        }
    
        private void bw_server_ProgressChanged(object sender, System.ComponentModel.ProgressChangedEventArgs e)
        {
            log(e.UserState.ToString());
        }
    
        private void bw_server_RunWorkerCompleted(object sender, System.ComponentModel.RunWorkerCompletedEventArgs e)
        {
            if (e.Cancelled)
            {
                log("Server was stopped");
            }
            else
            {
                log("Server work was completed");
            }
        }
    
        private void log(string msg)
        {
            if (String.IsNullOrEmpty(msg)) return;
            tb_log.AppendText((tb_log.Text == String.Empty ? String.Empty : Environment.NewLine) + DateTime.Now.ToLongTimeString() + " " + msg);
        }
    
        private void btn_stop_Click(object sender, EventArgs e)
        {
            WebRequest.Create("http://localhost:" + port + "/?stop=1").GetResponse();
            bw_server.CancelAsync();
        }
    
        private void start_server(string prefix)
        {
            server = new HttpListener();
            if (!HttpListener.IsSupported) return;
            if (String.IsNullOrEmpty(prefix))
            {
                throw new ArgumentException("prefix");
            }
            server.Prefixes.Add(prefix);
            server.Start();
            while (server.IsListening)
            {
                HttpListenerContext context = server.GetContext();
                HttpListenerRequest request = context.Request;
                if (request.HttpMethod == "GET")
                {
                    HttpListenerResponse response = context.Response;
                    response.ContentType = "text/html; charset=UTF-8";
                    if (request.QueryString["stop"] == "1")
                    {
                        write_to_resp(response, "server was stopped");
                        server.Stop();
                    }
                    else
                    {
                        write_to_resp(response, "bad params");
                    }
                }
            }
        }
    
        private static void write_to_resp(HttpListenerResponse response, string str_resp)
        {
            byte[] buffer = Encoding.UTF8.GetBytes(str_resp);
            response.ContentLength64 = buffer.Length;
            response.OutputStream.Write(buffer, 0, buffer.Length);
        }
    }