Обработка нескольких запросов с помощью C # HttpListener - PullRequest
14 голосов
/ 27 января 2012

У меня есть .NET Windows Service, которая порождает поток, который в основном действует как 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
    }
}

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

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

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

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

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

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

EDIT:

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

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

Ответы [ 3 ]

16 голосов
/ 27 января 2012

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

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

Посмотрите здесь .

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

9 голосов
/ 11 февраля 2015

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