使用C#HttpListener处理多个请求

Squ*_*onk 14 c# httplistener

我有一个.NET Windows服务,它产生一个基本上只是作为一个线程的线程HttpListener.这在同步模式示例中工作正常......

private void CreateLListener()
{
    HttpListenerContext context = null;
    HttpListener listener = new HttpListener();
    bool listen = true;

    while(listen)
    {
        try
        {
            context = listener.GetContext();
        }
        catch (...)
        {
            listen = false;
        }
        // process request and make response
    }
}
Run Code Online (Sandbox Code Playgroud)

我现在遇到的问题是我需要这个来处理多个请求并让它们同时响应或者至少以重叠的方式响应.

进一步解释 - 客户端是一个媒体播放器应用程序,它首先请求带有请求标头属性的媒体文件Range bytes=0-.据我所知,它可以解决媒体容器的问题.

在读取了"块"之后(或者如果它已经读取足以确定媒体类型),它就会发出另一个请求(来自不同的客户端套接字号)Range bytes=X-Y.在这种情况下,Y是第一个响应中返回的Content-Length,X比该值小250000个字节(使用IIS作为测试发现).在这个阶段,它正在获得最后一个"块",看它是否可以获得媒体时间戳来衡量长度.

读完之后,它会Range bytes=0-(从另一个套接字号)发出另一个请求,开始正确地流式传输媒体文件.

但是,在任何时候,如果客户端的用户执行"跳过"操作,则它发送另一个请求(来自另一个套接字号),Range bytes=Z-其中Z是要跳转到媒体文件中的位置.

我对HTTP的东西不是很好,但据我所知,我需要使用多个线程来处理每个请求/响应,同时允许原始文件HttpListener返回监听.我做了很多搜索,但找不到一个似乎合适的模型.

编辑:

感谢Rick Strahl对以下示例的感谢,我能够根据自己的需要进行调整......

使用几行代码将Web服务器添加到.NET 2.0应用程序中

use*_*188 16

如果您需要一个更简单的替代BeginGetContext的方法,您只能在ThreadPool中排队作业,而不是在主线程上执行它们.像这样:

private void CreateLListener() {
    //....
    while(true) {
        ThreadPool.QueueUserWorkItem(Process, listener.GetContext());    
    }
}
void Process(object o) {
    var context = o as HttpListenerContext;
    // process request and make response
}
Run Code Online (Sandbox Code Playgroud)

  • 完美的方式,但掌握Async编程将更好地为您服务 (3认同)

Ali*_*tad 11

您需要使用异步方法才能处理多个请求.所以你会使用e BeginGetContextEndGetContext方法.

看看这里.

如果您的应用程序在等待客户端请求时应该阻塞,并且您希望一次只处理一个 *请求*,则同步模型是合适的.使用同步模型,调用GetContext方法,该方法等待客户端发送请求.该方法返回一个HttpListenerContext对象,以便在发生时进行处理.

  • @MisterSquonk很高兴它对你有用.我们不在这里给鱼,但教钓鱼.:) (2认同)

gor*_*rdy 11

如果您来自未来并尝试使用async/await处理单个线程的多个并发请求.

public async Task Listen(string prefix, int maxConcurrentRequests, CancellationToken token)
{
    HttpListener listener = new HttpListener();
    listener.Prefixes.Add(prefix);
    listener.Start();

    var requests = new HashSet<Task>();
    for(int i=0; i < maxConcurrentRequests; i++)
        requests.Add(listener.GetContextAsync());

    while (!token.IsCancellationRequested)
    {
        Task t = await Task.WhenAny(requests);
        requests.Remove(t);

        if (t is Task<HttpListenerContext>)
        {
            var context = (t as Task<HttpListenerContext>).Result;
            requests.Add(ProcessRequestAsync(context));
            requests.Add(listener.GetContextAsync());
        }
    }
}

public async Task ProcessRequestAsync(HttpListenerContext context)
{
    ...do stuff...
}
Run Code Online (Sandbox Code Playgroud)

  • @LightLabyrinth 取消仅在收到请求后发生。如果没有请求,WhenAny 可以在没有请求进来时永远阻塞。 (2认同)