代码之家  ›  专栏  ›  技术社区  ›  Bob Mc

连续10个请求后的httpwebrequest超时

  •  6
  • Bob Mc  · 技术社区  · 17 年前

    我正在为一个特定的网站写一个网络爬虫。该应用程序是一个VB.NET Windows窗体应用程序,它是 使用多线程-每个Web请求都是连续的。但是,在成功地检索了10个页面之后,每个连续的请求都超时。

    我已经回顾了在这里发布的类似问题,并在getpage例程中实现了推荐的技术,如下所示:

    Public Function GetPage(ByVal url As String) As String
        Dim result As String = String.Empty
    
        Dim uri As New Uri(url)
        Dim sp As ServicePoint = ServicePointManager.FindServicePoint(uri)
        sp.ConnectionLimit = 100
    
        Dim request As HttpWebRequest = WebRequest.Create(uri)
        request.KeepAlive = False
        request.Timeout = 15000
    
        Try
            Using response As HttpWebResponse = DirectCast(request.GetResponse, HttpWebResponse)
                Using dataStream As Stream = response.GetResponseStream()
                    Using reader As New StreamReader(dataStream)
                        If response.StatusCode <> HttpStatusCode.OK Then
                            Throw New Exception("Got response status code: " + response.StatusCode)
                        End If
                        result = reader.ReadToEnd()
                    End Using
                End Using
                response.Close()
            End Using
    
        Catch ex As Exception
            Dim msg As String = "Error reading page """ & url & """. " & ex.Message
            Logger.LogMessage(msg, LogOutputLevel.Diagnostics)
        End Try
    
        Return result
    
    End Function
    

    我错过什么了吗?我是否没有关闭或处置一个应该关闭或处置的对象?奇怪的是,它总是发生在连续10个请求之后。

    笔记:

    1. 在这个方法所在的类的构造函数中,我有以下内容:

      ServicePointManager.DefaultConnectionLimit=100

    2. 如果我将keepalive设置为true,则超时将在五个请求之后开始。

    3. 所有请求都针对同一域中的页面。

    编辑

    我在每个Web请求之间添加了两到七秒的延迟,这样我就不会看起来像是在“锤击”站点或试图进行DoS攻击。但是,问题仍然存在。

    6 回复  |  直到 11 年前
        1
  •  3
  •   Paul van Brenk    17 年前

    我认为这个网站有某种DoS保护,当它受到许多rapis请求的攻击时,它就会启动。您可以尝试在WebRequest上设置UserAgent。

        2
  •  4
  •   Geoff    16 年前

    我今天遇到了这个问题,我的解决方案是确保随时停止响应。

    我认为您需要先放入response.close(),然后才能将异常抛出到using中。

    Using response As HttpWebResponse = DirectCast(request.GetResponse, HttpWebResponse) 
            Using dataStream As Stream = response.GetResponseStream() 
                Using reader As New StreamReader(dataStream) 
                    If response.StatusCode <> HttpStatusCode.OK Then 
                        response.Close()  
                        Throw New Exception("Got response status code: " + response.StatusCode) 
                    End If 
                    result = reader.ReadToEnd() 
                End Using 
            End Using 
            response.Close() 
        End Using
    
        3
  •  2
  •   Stephen Gerard Darragh    14 年前

    我使用了以下解决方案,它对我有效。希望对你也有帮助。

    在变量的窗体上声明“global”。

    HttpWebRequest myHttpWebRequest;
    HttpWebResponse myHttpWebResponse;
    

    然后总是使用 myHttpWebResponse.Close(); 每次连接后。

    myHttpWebResponse = (HttpWebResponse)myHttpWebRequest.GetResponse();
    myHttpWebResponse.Close();
    
        4
  •  1
  •   blue18hutthutt    12 年前

    我知道这是一个老问题,但最近我自己也遇到了这个问题(因为我的目标环境使用4.0,不允许任何外部程序集引用)

    不过,我进行了一些挖掘,发现了一种修复方法,从.NET内部工作的角度来看非常有趣。

    ServicePointManager.DefaultConnectionLimit = 100;
    

    ServicePointManager在内部处理由多个httpwebrequest对象创建的实际HTTP请求。问题是,这些不会自动关闭,httpwebrequest不会立即被垃圾收集。

    因此,我发现了一个非常有趣的问题,如果我让httpwebrequest成为一个实例级变量,并在将引用移出后强制垃圾收集,它会起作用(没有默认的connectionlimit=100 hack)

    private HttpWebRequest Request { get; set; }
    
    public void MyMethod() {
       Request = (HttpWebRequest)HttpWebRequest.Create("http://myUrl");
       GC.Collect();
       GC.WaitForFullGCComplete();
    }
    

    在我每次在方法中创建新的局部变量之前。这似乎解决了我的问题-可能有点晚了,没法帮助你,但我想我会分享,以防其他人遇到这种情况。

        5
  •  1
  •   Ldaniel    11 年前

    如果服务器正在使用数据库,并且没有正确关闭每个数据库连接,当达到最大连接限制时(直到数据库连接超时),您可能会收到一个错误(例如statuscode 502)。 在这种情况下,解决方案是在给定时间内“休眠”webrequest线程。 此外,您应该确保在处理后关闭每个请求和响应流(在最佳情况下,使用“using”语句):

        6
  •  0
  •   tmaj    15 年前

    myRequest.connection=“关闭”; 将使服务器关闭连接,从而使连接管理器也关闭连接。