使用 C# HttpListener 处理多个请求

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/9034721/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-09 05:42:04  来源:igfitidea点击:

Handling multiple requests with C# HttpListener

c#httplistener

提问by Squonk

I have a .NET Windows Service which spawns a thread that basically just acts as an HttpListener. This is working fine in synchronous mode example...

我有一个 .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
    }
}

The problem I now have is I need this to work with multiple requests and have them responded to simultaneously or at least in an overlapped way.

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

To explain further - the client is a media player app which starts by making a request for a media file with the request header property Range bytes=0-. As far as I can tell it does this to work out what the media container is.

进一步解释 - 客户端是一个媒体播放器应用程序,它首先使用请求标头属性请求媒体文件Range bytes=0-。据我所知,它这样做是为了确定媒体容器是什么。

After it has read a 'chunk' (or if it has read enough to ascertain media type) it then makes another request (from a different client socket number) with Range bytes=X-Y. In this case Y is the Content-Length returned in the first response and X is 250000 bytes less than that (discovered using IIS as a test). At this stage it is getting the last 'chunk' to see if it can get a media time-stamp to gauge length.

在它读取了一个“块”之后(或者如果它已经读取了足够的内容来确定媒体类型),它会使用Range bytes=X-Y. 在这种情况下,Y 是第一个响应中返回的内容长度,X 比它少 250000 字节(使用 IIS 作为测试发现)。在这个阶段,它正在获取最后一个“块”,看看它是否可以获得媒体时间戳来测量长度。

Having read that, it makes another request with Range bytes=0-(from another socket number) to start streaming the media file properly.

读完后,它发出另一个请求Range bytes=0-(来自另一个套接字号)以正确开始流式传输媒体文件。

At any time though, if the user of the client performs a 'skip' operation it then sends another request (from yet another socket number) with Range bytes=Z-where Z is the position to jump to in the media file.

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

I'm not very good with HTTP stuff but as far as I can tell I need to use multiple threads to handle each request/response while allowing the original HttpListenerto return to listening. I've done plenty of searching but can't find a model which seems to fit.

我不太擅长 HTTP 的东西,但据我所知,我需要使用多个线程来处理每个请求/响应,同时允许原始线程HttpListener返回侦听。我已经进行了大量搜索,但找不到似乎合适的模型。

EDIT:

编辑:

Acknowledgement and gratitude to Rick Strahl for the following example which I was able to adapt to suit my needs...

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

Add a Web Server to your .NET 2.0 app with a few lines of code

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

采纳答案by user1096188

If you need a more simple alternative to BeginGetContext, you can merely queue jobs in ThreadPool, instead of executing them on the main thread. Like such:

如果您需要一个更简单的 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
}

回答by Aliostad

You need to use the async method to be able to process multiple requests. So you would use e BeginGetContextand EndGetContextmethods.

您需要使用 async 方法才能处理多个请求。所以你会使用 eBeginGetContextEndGetContext方法。

Have a look here.

看看这里

The synchronous model is appropriate if your application should block while waiting for a client request and if you want to process only one*request at a time*. Using the synchronous model, call the GetContext method, which waits for a client to send a request. The method returns an HttpListenerContext object to you for processing when one occurs.

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

回答by gordy

If you're here from the future and trying to handle multiple concurrent requests with a single thread using async/await..

如果您从未来来到这里并尝试使用 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...
}