Вопрос

У нас есть довольно сложный httphandler для обработки изображений.По сути, он передает любую часть изображения любого запрошенного размера.Некоторые клиенты без проблем используют этот обработчик.Но у нас есть одно место, которое доставляет нам проблемы, а теперь оно также создает проблемы в моей среде разработки.

Происходит следующее: клиент никогда ничего не получает по некоторым запросам.Итак, запросы 1 и 2 подходят, но запросы 3 и 4 никогда не заканчиваются.

  • Во время отладки я вижу, что сервер готов и выполнил запрос.
  • Однако клиент все еще ожидает результата (отладка с помощью fiddler2 показывает, что ответ не получен).

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

        if (!context.Response.IsClientConnected)
        {
            imageStream.Close();
            imageStream.Dispose();
            return;
        }

        context.Response.BufferOutput = true;
        context.Response.ContentType = "image/" + imageformat;

        context.Response.AppendHeader("Content-Length", imageStream.Length.ToString());

        if (imageStream != null && imageStream.Length > 0 && context.Response.IsClientConnected)
            context.Response.BinaryWrite(imageStream.ToArray());

        if (context.Response.IsClientConnected)
            context.Response.Flush();

        imageStream.Close();
        imageStream.Dispose();

imageStream — это MemoryStream с содержимым изображения.

После вызова метода response.Flush() мы делаем еще одну очистку и записываем сводку в журнал событий.

Мы также вызываем GC.Collect() после каждого запроса, поскольку объекты, которые мы используем в памяти, становятся очень большими.Я знаю, что это не очень хорошая практика, но может ли это создать нам проблемы?

Проблемы с невозвратом запросов возникают как в IIS 5 (Win XP), так и в IIS 6 (Win 2003), мы используем .NET framework v2.

Это было полезно?

Решение

Клиент ограничивает количество одновременных запросов, которые он делает к любому серверу.Более того, при запросе ресурса, требующего состояния сеанса (по умолчанию), другие запросы ресурсов, требующих состояния сеанса, будут блокироваться.

Когда используешь HttpWebResponse вы должны удалить либо этот объект, либо поток, возвращаемый его GetResponseStream способ завершения соединения.

Ваш код был очень запутанным.Вы включили буферизацию, установили длину содержимого и использовали сброс.Это приводит к появлению странных HTTP-заголовков.Обычно при включенной буферизации вы оставляете настройку заголовка Content-Length на усмотрение ASP.NET.

При использовании сброса ASP.NET предполагает, что впоследствии вы можете отправить больше данных.В этом случае будет использоваться фрагментированная передача.После завершения ответа для последнего фрагмента отправляется окончательный набор заголовков, каждый фрагмент имеет собственный заголовок длины, и на основе них получается общая длина контента.Первый кусок должен нет иметь заголовок Content-Length, однако ваш код добавляет этот заголовок.

Если отключить буферизацию и самостоятельно закачивать байты в выходной поток затем вам следует установить заголовок Content-Length самостоятельно, поскольку эффективная буферизация означает, что вы берете на себя ответственность именно за то, что отправляется клиенту.Код Марка — простой пример такого насоса, хотя я бы использовал буфер большего размера, а в MemoryStream метод WriteTo был бы более эффективным.

Другие советы

Во-первых, есть более эффективные способы работы с потоками, использующие массив для всего этого (т. MemoryStream мощь здесь ненужно).

Я бы предусмотрел цикл:

const int BUFFER_SIZE = 4096; // pick your poison
bute[] buffer = new byte[BUFFER_SIZE];
int bytesRead;

while((bytesRead = inStream.Read(buffer, 0, BUFFER_SIZE)) > 0)
{
    outStream.Write(buffer, 0, bytesRead);
}

Вы также должны сделать это с отключенной буферизацией (.Response.BufferOutput = false).

Проблема в том, что я подозреваю, что вы не написали достаточно данных/закрыли ответ (.Response.Close()).

Сбор мусора не должен быть проблемой.Почему ты ставишь BufferOutput хотя правда?Учитывая, что вы просто хотите записать данные напрямую, я подумал, что было бы более уместно установить для него значение false.

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

Мы также использовали WebRequests для сбора дополнительной информации.Они блокировали соединения.Использование WebResponses помогло.

using (HttpWebResponse test_resp = (HttpWebResponse)test_req.GetResponse())
{
}

Я не знал, что они могут заблокировать другой запрос и т. д.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top