Тайм-аут с HttpWebResponse в .NET

У меня есть следующий код, и после его вызова ~ 60 раз (20 одновременных подключений) начинается тайм-аут. если я уменьшу время ожидания с 10 минут до 1 минуты, они начнут отключаться при ~ 34 загрузках. что дает? Я знаю, что вы можете получить это, если не закроете свой ответ должным образом, но я определенно закрываю его:

    //===============================================================================
    /// <summary>
    /// Executes the request and returns the response as a byte array. Useful if the 
    /// response should return a file.
    /// </summary>
    private static byte[] GetResponse(HttpWebRequest webRequest)
    {
        //---- declare vars
        HttpWebResponse response = null;
        List<byte> buffer = new List<byte>();
        int readByte;

        //---- try to get the response, always wrap it.
        try
        { response = webRequest.GetResponse() as HttpWebResponse; }
        //---- catch all
        catch (Exception e)
        {
            if (response != null) { response.Close(); }
            throw new ConnectionFailedException("Failed to get a response", e);
        }

        try
        {
            //---- if the response is ok
            if (response.StatusCode == HttpStatusCode.OK)
            {
                //---- get the response stream
                using (Stream stream = response.GetResponseStream())
                {
                    //---- read each byte, one by one into the byte buffer
                    while ((readByte = stream.ReadByte()) > -1)
                    {
                        buffer.Add((byte)readByte);
                    }
                    //---- close the stream
                    stream.Close();
                    response.Close();
                }

                //---- return the buffer as a byte array
                return buffer.ToArray();
            }
            //---- if the request wasn't auth'd
            else if (response.StatusCode == HttpStatusCode.Forbidden || response.StatusCode == HttpStatusCode.Unauthorized)
            {
                if (response != null) { response.Close(); }
                throw new AuthenticationFailedException(response.StatusDescription);
            }
            //---- any other errors
            else
            {
                if (response != null) { response.Close(); }
                throw new ConnectionFailedException(response.StatusDescription);
            }
        }
        finally { if (response != null) { response.Close(); } }
    }
    //===============================================================================

мысли?

Кроме того, я создаю его с TimeOut и ReadWriteTimeout, установленным на 10 минут:

// ---- создаем веб-запрос HttpWebRequest webRequest = WebRequest.Create (url) as HttpWebRequest;

// ---- установим тайм-аут 10 минут webRequest.Timeout = 600000; webRequest.ReadWriteTimeout = 600000;


person bryan costanich    schedule 28.10.2010    source источник


Ответы (4)


System.Net.ServicePointManager.DefaultConnectionLimit = 200;

^^ сделано.

вот и все.

person bryan costanich    schedule 29.10.2010

Как насчет того, чтобы немного упростить код:

using (var client = new WebClient())
{
    byte[] result = client.DownloadData("http://example.com");
}
person Darin Dimitrov    schedule 28.10.2010
comment
не может использовать WebClient. необходимо указать настраиваемые заголовки и аутентификацию. - person bryan costanich; 28.10.2010
comment
@bryan, client.Headers["Custom-Header"] = "Custom value" и client.Credentials. - person Darin Dimitrov; 28.10.2010
comment
Возможно, мне придется пойти по этому пути, но были и другие причины, по которым я не мог использовать его изначально, я не помню, что они были. некоторые ограничения с WebClient. - person bryan costanich; 28.10.2010
comment
@bryan, ограничений нет. Только упрощение вашего кода. Все, что вы могли сделать с HttpWebRequest, вы могли бы сделать с помощью WebClient (за исключением некоторых случаев, когда вам может потребоваться написать собственный WebClient и переопределить методы - например, если вы хотите использовать контейнер cookie). - person Darin Dimitrov; 28.10.2010
comment
Я перестроился на использование WebClient и получаю те же таймауты ответа, что и раньше. - person bryan costanich; 28.10.2010
comment
я знал, что у WebClient есть ограничение. вы не можете устанавливать тайм-ауты в веб-клиенте, если не подклассифицируете его. Я подклассифицировал, переопределил тайм-аут, но у меня все еще та же проблема. - person bryan costanich; 28.10.2010

Установите для свойства KeepAlive значение false:

webRequest.KeepAlive = false;

Освободите ресурс в операторе finally.

person Shelvin    schedule 28.10.2010
comment
это может быть оно. Я помню, что приходилось делать это где-то раньше, теперь, когда вы об этом упомянули. сейчас тестирую. Я дам Вам знать. - person bryan costanich; 28.10.2010
comment
ага, это не помогло. :( Вероятно, придется просто использовать веб-клиент. - person bryan costanich; 28.10.2010

Не проверено, но немного чище.

private static byte[] GetResponse(HttpWebRequest webRequest)
{
        using (var response = (HttpWebResponse)webRequest.GetResponse())
        {
            switch (response.StatusCode)
            {
                case HttpStatusCode.Forbidden:
                case HttpStatusCode.Unauthorized:
                    throw new AuthenticationFailedException(response.StatusDescription);
                    break;
                case HttpStatusCode.OK:
                    break; // to get through
                default:
                    throw new ConnectionFailedException(response.StatusDescription);
            }

            using (Stream stream = response.GetResponseStream())
            {
                // you should really create a large buffer and read chunks.
                var buffer = new byte[response.ContentLength];
                var bytesRead = 0;
                while (bytesRead < buffer.Length)
                {
                   var bytes = stream.Read(buffer, bytesRead, buffer.Length - bytesRead);
                   bytesRead += bytes;
                }

                return buffer;
            }

        }
}

Изменить:

Изменено так, что для выделения буфера используется ContentLength. Это всегда точно, если не используется кодирование по частям.

person jgauffin    schedule 28.10.2010
comment
не нравится буфер, потому что длина ненадежна, вы не всегда знаете длину. поэтому альтернативой является создание буфера фиксированного размера, и когда вы его заполняете, создаете другой, копируете для изменения размера и т. д. менее эффективно, чем просто использование списка байтов и выполнение одной окончательной копии. - person bryan costanich; 28.10.2010
comment
Проверьте измененный код. Кроме того, добавление одного байта за раз кажется не очень эффективным. Список должен выделять новый внутренний буфер время от времени, делая это по-своему (вы можете зарезервировать размер, чтобы предотвратить это, проверьте параметр емкости в конструкторе). - person jgauffin; 28.10.2010