Обработка нескольких запросов с помощью 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
    }
}

проблема, которую я сейчас имею, заключается в том, что мне нужно работать с несколькими запросами и отвечать на них одновременно или, по крайней мере, перекрывать.

чтобы объяснить дальше-клиент-это приложение media player, которое начинается с запроса медиа-файла со свойством заголовка запроса Range bytes=0-. Как насколько я могу судить, он делает это, чтобы выяснить, что такое медиа-контейнер.

после того, как он прочитал "кусок" (или если он прочитал достаточно, чтобы установить тип носителя), он делает другой запрос (из другого номера сокета клиента) с Range bytes=X-Y. В этом случае Y-длина содержимого, возвращаемая в первом ответе, а X-на 250000 байт меньше (обнаружено с помощью IIS в качестве теста). На этом этапе он получает последний "кусок", чтобы увидеть, может ли он получить метку времени мультимедиа для измерения длина.

прочитав это, он делает еще один запрос с Range bytes=0- (С другого номера сокета), чтобы правильно начать потоковую передачу медиафайла.

в любое время, хотя, если пользователь клиента выполняет операцию "пропустить", он отправляет другой запрос (из еще одного номера сокета) с Range bytes=Z- где Z-позиция для перехода в медиафайле.

Я не очень хорошо разбираюсь в HTTP-материалах, но, насколько я могу судить, мне нужно использовать несколько потоков для обработки каждого запрос / ответ, разрешая оригинал HttpListener вернуться к прослушиванию. Я много искал, но не могу найти модель, которая, кажется, подходит.

EDIT:

признание и благодарность Рик Штраль на следующем примере, который я смог адаптироваться, чтобы удовлетворить мои потребности...

добавьте веб-сервер в приложение .NET 2.0 с несколькими строками кода

3 ответов


Если вам нужна более простая альтернатива 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
}

для обработки нескольких запросов необходимо использовать метод async. Таким образом, вы будете использовать e BeginGetContext и EndGetContext методы.

посмотреть здесь.

синхронный модель подходит, если ваше приложение должно блокировать в ожидании запроса клиента и если вы хотите обработать только один *запрос в то время*. Используя синхронную модель, вызовите GetContext метод, ожидающий клиента отправить запрос. Метод возвращает объект HttpListenerContext для обработки при его возникновении.


Если вы здесь из будущего и пытаетесь обработать несколько параллельных запросов с помощью одного потока, используя 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...
}