HttpWebRequest在第二次调用时超时

时间:2011-04-29 01:47:22

标签: c# http garbage-collection httpwebrequest webrequest

为什么以下代码超时运行第二个(及后续)时间?

代码挂起:

using (Stream objStream = request.GetResponse().GetResponseStream())

然后导致WebException表示请求已超时。

我已尝试使用WebRequestHttpWebRequest

编辑:似乎代码在request.GetResponse()

中失败了

编辑:这篇文章表明它可能是GC问题 - > http://www.vbforums.com/showthread.php?t=610043 - 根据这篇文章,如果Fiddler在后台开放,问题就会得到缓解。

服务器在那里,可用于请求。

    private string GetQLMResponse(string URL)
    {
        HttpWebRequest request = WebRequest.Create(URL) as HttpWebRequest;
        request.Credentials = new NetworkCredential(Settings.Default.LicenseUser, Settings.Default.LicensePassword);
        request.KeepAlive = false;
        request.Timeout = 5000;
        request.Proxy = null;

        // Read stream
        string responseString = String.Empty;
        try
        {
            using (var response = request.GetResponse())
            {
                using (Stream objStream = response.GetResponseStream())
                {
                    using (StreamReader objReader = new StreamReader(objStream))
                    {
                        responseString = objReader.ReadToEnd();
                        objReader.Close();
                    }
                    objStream.Flush();
                    objStream.Close();
                }
                response.Close();
            }
        }
        catch (WebException ex)
        {
            throw new LicenseServerUnavailableException();
        }
        finally
        {
            request.Abort();
            request = null;
            GC.Collect();
        }
        return responseString;
    }

抛出WebException:

  

{“操作已超时”}       [System.Net.WebException]:{“操作已超时”}       数据:{System.Collections.ListDictionaryInternal}       HelpLink:null       InnerException:null       消息:“操作已超时”       来源:“系统”       StackTrace:“在System.Net.HttpWebRequest.GetResponse()\ r \ n,位于C:\ Users \ jd \ SVN \ jd \ Products \ Development \ JAD.Licensing \ JAD中的IQX.Licensing.License.GetQLMResponse(字符串URL) .Licensing \ License.cs:第373行“       TargetSite:{System.Net.WebResponse GetResponse()}


更新:确定以下代码现在可以使用了。 servicePoint将超时设置为接近4分钟。更改请求对象上的ServicePoint.ConnectionLeaseTimeout意味着请求现在在5000ms后被销毁。感谢大家的帮助以及这2页:

  1. http://blogs.msdn.com/b/adarshk/archive/2005/01/02/345411.aspx
  2. http://msdn.microsoft.com/en-us/library/6hszazfz(v=VS.80).aspx

    private string GetQLMResponse(string URL)
    {
        HttpWebRequest request = WebRequest.Create(URL) as HttpWebRequest;
        request.Credentials = new NetworkCredential(Settings.Default.LicenseUser, Settings.Default.LicensePassword);
        request.KeepAlive = false;
        request.Timeout = 5000;
        request.Proxy = null;
    
        request.ServicePoint.ConnectionLeaseTimeout = 5000;
        request.ServicePoint.MaxIdleTime = 5000;
    
        // Read stream
        string responseString = String.Empty;
        try
        {
            using (WebResponse response = request.GetResponse())
            {
                using (Stream objStream = response.GetResponseStream())
                {
                    using (StreamReader objReader = new StreamReader(objStream))
                    {
                        responseString = objReader.ReadToEnd();
                        objReader.Close();
                    }
                    objStream.Flush();
                    objStream.Close();
                }
                response.Close();
            }
        }
        catch (WebException ex)
        {
            throw new LicenseServerUnavailableException();
        }
        finally
        {
            request.Abort();
        }
        return responseString;
    }
    

8 个答案:

答案 0 :(得分:27)

在之前的答案之后,我想补充一些东西。默认情况下,HttpWebRequest只允许2个连接到同一主机(这是HTTP 1.1“niceness”),

是的,可以覆盖,不,我不会告诉你如何在这个问题上,你要问另一个:) 我认为你应该看看this post

我认为您仍然没有完全处理与HttpWebRequest相关的所有资源,因此连接池发挥作用,这就是问题所在。我不会尝试对每个服务器规则的2个连接进行打击,除非你真的需要。

正如上面提到的其中一张海报,Fiddler在这种情况下对你有点不利。

我会在你的catch之后添加一个很好的finally {}子句,并确保如上面的帖子所述,所有流都被刷新,关闭,并且对请求对象的引用被设置为null。

如果有帮助,请告诉我们。

答案 1 :(得分:21)

WebResponse获得的request.GetReponse()必须妥善处理。试试这个(删除request.Abort()GC.Collect()来电):

using (var wresponse = request.GetResponse())
{
   using (Stream objStream = wresponse.GetResponseStream())
   {
        // ...
   }
}

修改: 由于它仍然无效,我建议您使用空的Windows应用程序进行测试。这样,您可以隔离app.config问题或每个主机的最大并发调用*(您是否在应用程序中的其他位置使用其他webrequest对象到此主机;哪些webresponse未正确处理?)。

希望这能解决你的问题,我没有想法!

  • 请参阅Jon Skeet的回答here

答案 2 :(得分:8)

正如您所说,在后台运行提琴手可以缓解这个问题。这是因为提琴手力量会关闭任何回应。从Sam B扩展上述帖子,我将确保响应如此关闭:

using (var wresponse = request.GetResponse())
{
   using (Stream objStream = wresponse.GetResponseStream())
   {
        // ...
   } 
   wresponse.close();
}

也可能值得将代理设置为null,如下所示:

 request.Proxy = Null;

由于.NET框架将会搜索代理,除非您明确这样做。当fiddler正在运行时,这种效果会被减轻,因为可以直接找到小提琴代理。

答案 3 :(得分:4)

尽管正确处理/刷新/关闭所有内容,

在后续请求服务器时遇到了同样的问题。尝试刷新你的连接组,为我工作:

myRequest.ServicePoint.CloseConnectionGroup(myRequest.ConnectionGroupName);

另外,请确保您不会无意中在应用程序的其他位置创建未正确终止/处置的其他HttpWebRequest / Request对象,因为这会增加服务点中的连接数。

答案 4 :(得分:1)

我遇到了同样的问题,我解决了这个问题,确保我在每个创建的请求对象上调用 Abort() 方法。

答案 5 :(得分:0)

您是否有机会使用默认名称为WindowsFormsApp N 的测试应用程序?我有同样的问题,我花了一个星期的调试,因为它在我的生产代码中工作,但不是在我正在构建的简单测试解决方案。最后,我确定这种行为对于使用默认解决方案名称而不是正确命名的解决方案是唯一的。

编辑:我发现我的问题与使用BitDefender作为我的AV软件有关。 WindowsFormsApp N 程序全部被阻止。

答案 6 :(得分:0)

我阅读了上面标记为答案的帖子,但上面的内容对我而言确实无效。 我最终使用using标记重写了代码,并在此处推荐了其他人推荐的CloseConnectionGroup段。最终,代码如下所示:

System.Net.HttpWebRequest webRequest = (System.Net.HttpWebRequest)System.Net.HttpWebRequest.Create(imageUrl);
                webRequest.AllowWriteStreamBuffering = true;
                webRequest.Timeout = 30000;
                webRequest.ServicePoint.ConnectionLeaseTimeout = 5000;
                webRequest.ServicePoint.MaxIdleTime = 5000;

                using (System.Net.WebResponse webResponse = webRequest.GetResponse())
                {

                    using (System.IO.Stream stream = webResponse.GetResponseStream())
                    {
                        image = System.Drawing.Image.FromStream(stream);
                    }
                }

                webRequest.ServicePoint.CloseConnectionGroup(webRequest.ConnectionGroupName);
                webRequest = null; 
            }

答案 7 :(得分:-3)

我已将http时间设置为10分钟,这对我有用。

设置为timeout=infinite花费了更多时间,我的程序进入挂起模式。