C#使用HTTPListener异步实现HTTP服务端,请求执行两次

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C#使用HTTPListener异步实现HTTP服务端,请求执行两次相关的知识,希望对你有一定的参考价值。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Net.Sockets;
using DevSDK.Net.Sockets;
using System.IO;

namespace ConsoleApplication1

class Program

static HttpListener sSocket = null;

static void Main(string[] args)

sSocket = new HttpListener();
sSocket.Prefixes.Add("http://127.0.0.1:8080/");
sSocket.Start();
sSocket.BeginGetContext(new AsyncCallback(GetContextCallBack), sSocket);
Console.Read();

static void GetContextCallBack(IAsyncResult ar)

try

sSocket = ar.AsyncState as HttpListener;
HttpListenerContext context = sSocket.EndGetContext(ar);

sSocket.BeginGetContext(new AsyncCallback(GetContextCallBack), sSocket);

// 该方法是我要进行的操作
CommonMethod();

catch



参考技术A 你是执行2次CommonMethod()?那可以用for循环啊。追问

不是,我只想一个请求执行一次,但是一个请求进来后却执行了两次后,才会停下来等待接收另一个请求

参考技术B

不知道你的请求是否是从浏览器访问的,我的是浏览器访问,执行2次的原因是因为确实请求2次,具体看截图。

异步 HttpListener 每个请求被接收两次

【中文标题】异步 HttpListener 每个请求被接收两次【英文标题】:Asynchronous HttpListener has each request is received twice 【发布时间】:2011-05-05 08:57:39 【问题描述】:

我在 C# 中实现了一个异步 http 监听器。

我按照here by Microsoft提供的教程进行操作

发现了另一个教程,我愚蠢地没有加入书签,现在再也找不到了。这意味着我有一些我不会自己编写的代码,但提供的解释是有道理的,所以我遵循了。

现在我面临两个问题:

首先,我必须在每次请求后使用 Listener.Stop() 重新启动侦听器,然后再次调用 StartListening 方法,其次,当我这样做时,我会收到每个请求两次。 该请求确实被发送了两次,但我收到了两次。 但是,当我暂停正在收听的线程约 2 秒时,它不会收到两次。

如果我的解释含糊不清,我很抱歉,但我对我的问题的理解也是如此,我不知道是什么原因造成的。 由于回调方法是大多数事情发生的地方,所以我将发布它,如果您需要更多代码,请告诉我。 任何帮助将不胜感激,因为我真的坚持这个。

public void ListenAsynchronously()
    

        if (listener.Prefixes.Count == 0) foreach (string s in prefixes) listener.Prefixes.Add(s);

        try
        
            listener.Start();
        
        catch (Exception e)
        
            Logging.logException(e); 
        

        System.Threading.ThreadPool.QueueUserWorkItem(new System.Threading.WaitCallback(Listen));
    


    private void Listen(object state)
    
        while (listener.IsListening)
        
            listener.BeginGetContext(new AsyncCallback(ListenerCallback), listener);
            listenForNextRequest.WaitOne();
        
    
     private void ListenerCallback(IAsyncResult ar)
    

        HttpListener httplistener = ar.AsyncState as System.Net.HttpListener;
        System.Net.HttpListenerContext context = null;

        int requestNumber = System.Threading.Interlocked.Increment(ref requestCounter);

        if (httplistener == null) return;

        try
        
            context = httplistener.EndGetContext(ar);
        
        catch(Exception ex)
        
            return;
        
        finally
        
            listenForNextRequest.Set();
        

        if (context == null) return;


        System.Net.HttpListenerRequest request = context.Request;

        if (request.HasEntityBody)
        
            using (System.IO.StreamReader sr = new System.IO.StreamReader(request.InputStream, request.ContentEncoding))
            
                string requestData = sr.ReadToEnd();

                //Stuff I do with the request happens here

            
        


        try
        
            using (System.Net.HttpListenerResponse response = context.Response)
            
                //response stuff happens here

                

                byte[] buffer = System.Text.Encoding.UTF8.GetBytes(responseString);
                response.ContentLength64 = buffer.LongLength;
                response.OutputStream.Write(buffer, 0, buffer.Length);
                response.Close();


                StopListening();
                //If I dont set the thread to sleep here, I receive the double requests
                System.Threading.Thread.Sleep(2500);

                ListenAsynchronously(); 


            
        
        catch (Exception e)
        
        

    

【问题讨论】:

不知道是什么调用了这个回调,不知道WaitHandle的listenForNextRequest是怎么用的,ListenAsynchronously做了什么方法,有点猜谜游戏。 对不起,我添加了代码 您应该将一些有用的调试信息打印到控制台(或记录到文件,如果您愿意)并在此处发布。请指定您用于运行此代码的操作系统及其版本。这样会更简单地尝试帮助您...问候,贾科莫 【参考方案1】:

我不确定您为什么在您的 ListenerCallback() 方法中调用 StopListening()ListenAsynchronously()Listen() 方法正在线程中运行,并将继续获取每个下一个传入请求。如果我在写这个,我就不会使用 HttpListener 的实例变量。在您的 ListenAsynchronously 方法中创建一个新的并将其传递到您的状态对象中,例如,

public class HttpListenerCallbackState

    private readonly HttpListener _listener;
    private readonly AutoResetEvent _listenForNextRequest;

    public HttpListenerCallbackState(HttpListener listener)
    
        if (listener == null) throw new ArgumentNullException("listener");
        _listener = listener;
        _listenForNextRequest = new AutoResetEvent(false);
    

    public HttpListener Listener  get  return _listener;  
    public AutoResetEvent ListenForNextRequest  get  return _listenForNextRequest;  


public class HttpRequestHandler

    private int requestCounter = 0;
    private ManualResetEvent stopEvent = new ManualResetEvent(false);

    public void ListenAsynchronously(IEnumerable<string> prefixes)
    
        HttpListener listener = new HttpListener();

        foreach (string s in prefixes)
        
            listener.Prefixes.Add(s);
        

        listener.Start();
        HttpListenerCallbackState state = new HttpListenerCallbackState(listener);
        ThreadPool.QueueUserWorkItem(Listen, state);
    

    public void StopListening()
    
        stopEvent.Set();
    


    private void Listen(object state)
    
        HttpListenerCallbackState callbackState = (HttpListenerCallbackState)state;

        while (callbackState.Listener.IsListening)
        
            callbackState.Listener.BeginGetContext(new AsyncCallback(ListenerCallback), callbackState);
            int n = WaitHandle.WaitAny(new WaitHandle[]  callbackState.ListenForNextRequest, stopEvent);

            if (n == 1)
            
                // stopEvent was signalled 
                callbackState.Listener.Stop();
                break;
            
        
    

    private void ListenerCallback(IAsyncResult ar)
    
        HttpListenerCallbackState callbackState = (HttpListenerCallbackState)ar.AsyncState;
        HttpListenerContext context = null;

        int requestNumber = Interlocked.Increment(ref requestCounter);

        try
        
            context = callbackState.Listener.EndGetContext(ar);
        
        catch (Exception ex)
        
            return;
        
        finally
        
            callbackState.ListenForNextRequest.Set();
        

        if (context == null) return;


        HttpListenerRequest request = context.Request;

        if (request.HasEntityBody)
        
            using (System.IO.StreamReader sr = new System.IO.StreamReader(request.InputStream, request.ContentEncoding))
            
                string requestData = sr.ReadToEnd();

                //Stuff I do with the request happens here  
            
        


        try
        
            using (HttpListenerResponse response = context.Response)
            
                //response stuff happens here  
                string responseString = "Ok";

                byte[] buffer = Encoding.UTF8.GetBytes(responseString);
                response.ContentLength64 = buffer.LongLength;
                response.OutputStream.Write(buffer, 0, buffer.Length);
                response.Close();
            
        
        catch (Exception e)
        
        
    

【讨论】:

我用它作为从 .Net 2.0 应用程序中提供简单页面的基础,我对它的运行效果印象深刻。在我的笔记本电脑上,我能够为一个简单的单线程负载测试脚本每秒处理大约 130-200 个请求,同时为该测试脚本的 5 个实例中的每一个实例提供大约 20 个请求。在这些测试中,服务器代码使用了我大约 12% 的 CPU。

以上是关于C#使用HTTPListener异步实现HTTP服务端,请求执行两次的主要内容,如果未能解决你的问题,请参考以下文章

http 异步 接收 回传 数据文字和文件流

通过HttpListener实现简单的Http服务

使用 C# HttpListener 处理多个请求

使用 C# HttpListener 提供大文件

使用 C# HttpListener 时无法设置 MIME 类型

HttpListener 的 CORS 访问