【问题标题】:Timeout with HttpWebResponse in .NET.NET 中的 HttpWebResponse 超时
【发布时间】:2010-10-28 07:02:59
【问题描述】:

我有以下代码,在调用它约 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;

【问题讨论】:

    标签: .net httpwebrequest httpwebresponse


    【解决方案1】:

    System.Net.ServicePointManager.DefaultConnectionLimit = 200;

    ^^ 完成。

    就是这样。

    【讨论】:

      【解决方案2】:

      稍微简化一下你的代码怎么样:

      using (var client = new WebClient())
      {
          byte[] result = client.DownloadData("http://example.com");
      }
      

      【讨论】:

      • 无法使用 WebClient。需要指定自定义标头和身份验证。
      • @bryan、client.Headers["Custom-Header"] = "Custom value"client.Credentials
      • 我可能不得不这样做,但还有其他原因我最初无法使用它,我不记得它们是什么了。 WebClient 的一些限制。
      • @bryan,没有限制。仅简化您的代码。您可以使用 HttpWebRequest 执行的所有操作都可以使用 WebClient 执行(除了某些情况下您可能需要编写自定义 WebClient 并覆盖方法 - 例如,如果您想使用 cookie 容器)。
      • 我重构为使用 WebClient,得到的响应超时与以前相同。
      【解决方案3】:

      通过以下方式将 KeepAlive 属性设置为 false:

      webRequest.KeepAlive = false;
      

      在 finally 语句中释放资源。

      【讨论】:

      • 可能就是这样。我记得以前在某个地方必须这样做,现在你提到了。我现在正在测试。我会告诉你的。
      • 哎呀,这并没有解决它。 :( 可能只需要使用 webclient。
      【解决方案4】:

      未经测试,但更干净一些。

      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。除非使用分块编码,否则它总是准确的。

      【讨论】:

      • 不喜欢缓冲区的东西,因为长度不可靠,你并不总是知道长度。所以另一种方法是创建一个固定的缓冲区大小,当你填满它时,创建另一个,复制到调整大小等。效率低于仅使用字节列表并进行最终复制。
      • 检查修改后的代码。此外,一次添加一个字节似乎效率不高。该列表需要不时按您的方式分配一个新的内部缓冲区(您可以保留一个大小来防止这种情况,检查构造函数中的容量参数)。
      猜你喜欢
      • 2019-09-06
      • 2013-04-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多