2009-07-28 17 views
6

Estoy escribiendo un rastreador web para un sitio específico. La aplicación es una aplicación de Windows Forms de VB.Net que es que no es que utiliza varios subprocesos: cada solicitud web es consecutiva. Sin embargo, después de diez recuperaciones de página exitosas, cada solicitud sucesiva agota el tiempo de espera.Tiempo de espera HttpWebRequest después de diez solicitudes consecutivas

He revisado las preguntas similares ya publicados aquí en SO, y han aplicado las técnicas recomendadas en mi rutina getPage, que se muestran a continuación:

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 

¿Me he perdido algo? ¿No estoy cerrando o eliminando un objeto que debería ser? Parece extraño que siempre suceda después de diez solicitudes consecutivas.

Notas:

  1. En el constructor de la clase en la que este método reside he lo siguiente:

    ServicePointManager.DefaultConnectionLimit = 100

  2. Si fijo KeepAlive true, los tiempos de espera comienzan después de cinco solicitudes.

  3. Todas las solicitudes están para páginas en el mismo dominio.

EDITAR

he añadido un retardo entre cada solicitud Web de entre dos y siete segundos, de modo que no parecen estar "martilleo" del sitio o de intentar un ataque DoS. Sin embargo, el problema aún ocurre.

+0

¿Cuál es el nombre del producto y la versión del servidor web que aloja la aplicación? – David

+0

Hay un límite de 10 conexiones a IIS 5 – David

+0

Tengo curiosidad, ¿alguna vez has identificado la causa? Me estoy encontrando con el mismo problema. –

Respuesta

3

Creo que el sitio tiene algún tipo de protección de DOS, que se activa cuando se produce una serie de solicitudes de violación. Puede intentar configurar el User Agents en la webrequest.

+0

Gracias por la respuesta. Si la causa es la protección de DOS, ¿por qué la diferencia en los tiempos de espera cuando KeepAlive es verdadera y cuando KeepAlive es falsa? –

+0

El establecimiento de UserAgent mejoró la situación. Todavía tengo algunos tiempos de espera, pero son más aleatorios y menos frecuentes. Entonces, antes de marcar esto como correcto, ¿puede expandir su respuesta para indicar por qué configurar UserAgent tiene este efecto? –

+0

Después de más pruebas, ayuda un poco, pero finalmente obtengo un tiempo de espera en una página y en todas las páginas sucesivas, así que estoy empezando a creer en la teoría de protección de DOS. –

4

Me encontré con este problema hoy y mi resolución fue asegurarme de que la respuesta estuviera cerrada en todo momento.

Creo que debe enviar una respuesta. Cierre() antes de lanzar la excepción dentro del uso.

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 
+2

@Geoff: el 'Using response' asegura que la respuesta se cierre. –

+0

@Geoff: Lo intenté de todos modos, pero no ayudó. Creo que John está en lo correcto: el 'Uso de la respuesta' debería ocuparse de cerrar las cosas correctamente. Gracias por la respuesta. –

+0

Permítanme comentar que el comentario de John me proporcionó una solución (tener un problema similar: tiempos de espera después de las solicitudes posteriores). –

0

myRequest.Connection = "Cerrar"; hará que el servidor cierre la conexión, lo que hará que el administrador de conexión también cierre la conexión.

+0

Gracias Tymek. Agregué esto a mi código pero arroja una excepción que dice "Keep-Alive and Close no se puede establecer con esta propiedad. Nombre del parámetro: valor". He encontrado poco a través de Google con respecto a lo que esto significa. ¿Te encontraste con este problema? Si es así, ¿cómo lo corrigió? –

2

Utilicé la siguiente solución y me funciona. Espero que te ayude también.

Declara "global" en el formulario las variables.

HttpWebRequest myHttpWebRequest; 
HttpWebResponse myHttpWebResponse; 

utilice siempre myHttpWebResponse.Close(); después de cada conexión.

myHttpWebResponse = (HttpWebResponse)myHttpWebRequest.GetResponse(); 
myHttpWebResponse.Close(); 
1

Sé que esta es una pregunta anterior, pero recientemente tuve este problema yo mismo (debido a mi entorno de destino con 4.0 y no permitir ninguna referencia de montaje externo)

lo hice algo de investigación, sin embargo, y encontraron una solución de tipo y es muy interesante desde el punto de vista funcionamiento interno .NET

ServicePointManager.DefaultConnectionLimit = 100; 

ServicePointManager maneja internamente la solicitud HTTP real creado por múltiples objetos HttpWebRequest ..problem es, estos no se cierran automáticamente y HttpWebRequest no obtiene basura recolectada inmediatamente

Así que encontré algo muy interesante - si hago HttpWebRequest una variable de nivel de instancia Y fuerzo la recolección de basura después de cambiar la referencia ce a cabo ... funciona (sin el DefaultConnectionLimit = 100 truco)

private HttpWebRequest Request { get; set; } 

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

Antes de que yo estaba creando una nueva variable local cada vez que en el método. Esto pareció solucionar mi problema, probablemente fue demasiado tarde para ayudarlo, pero pensé en compartirlo en caso de que alguien se encuentre con este

1

Si el servidor utiliza una base de datos y no cierra correctamente cada conexión de la base de datos, puede recibir un error (p. ej., código de estado 502) cuando el máx. se alcanza la conexión limitada (hasta el tiempo de espera de conexión de la base de datos). Una solución en este caso es solo para 'dormir' el hilo webrequest por un tiempo dado. Además, debe asegurarse de que cada solicitud y flujo de respuesta se cierra después del procesamiento (en el mejor de los casos utilizando una instrucción 'Uso'):

Cuestiones relacionadas