2009-08-01 215 views
25

Tengo un gran problema: necesito enviar 200 objetos a la vez y evitar los tiempos de espera.System.Net.WebException: la operación ha excedido el tiempo de espera

while (true) 
{ 

    NameValueCollection data = new NameValueCollection(); 
    data.Add("mode", nat); 

    using (var client = new WebClient()) 
    { 
     byte[] response = client.UploadValues(serverA, data); 
     responseData = Encoding.ASCII.GetString(response); 

     string[] split = Javab.Split(new[] { '!' }, StringSplitOptions.RemoveEmptyEntries); 
     string command = split[0]; 
     string server = split[1]; 
     string requestCountStr = split[2]; 

     switch (command) 
     { 
      case "check": 
       int requestCount = Convert.ToInt32(requestCountStr); 

       for (int i = 0; i < requestCount; i++) 
       { 
        Uri myUri = new Uri(server); 
        WebRequest request = WebRequest.Create(myUri); 
        request.Timeout = 200000; 
        WebResponse myWebResponse = request.GetResponse(); 
       } 
       break; 
     } 
    }  
} 

Esto produce el error:

Unhandled Exception: System.Net.WebException: The operation has timed out 
at System.Net.HttpWebRequest.GetResponse() 
at vir_fu.Program.Main(String[] args) 

El bucle requestCount funciona bien fuera de mi código de base, pero cuando lo añado a mi proyecto me sale este error. He intentado configurar request.Timeout = 200; pero no sirvió.

+1

Por cierto, cuando publique código, intente publicar código real. Su código no compilaría: el constructor 'WebRequest' está' protected'. También sería conveniente si en lugar de "...", usara "// ...". –

Respuesta

0

Recuerdo que tuve el mismo problema hace un tiempo usando WCF debido a la cantidad de datos que estaba pasando. Recuerdo que cambié los tiempos de espera en todas partes, pero el problema persistía. Lo que finalmente hice fue abrir la conexión como solicitud de transmisión, necesitaba cambiar el lado del cliente y del servidor, pero funciona de esa manera. Como era una conexión de transmisión, el servidor siguió leyendo hasta que terminó la transmisión.

32

Significa lo que dice. La operación tomó demasiado tiempo para completarse.

Por cierto, mira WebRequest.Timeout y verá que que haya definido su tiempo de espera para 1/5 de segundo.

24

No estoy seguro acerca de su primer ejemplo de código donde usa WebClient.UploadValues, no es suficiente para continuar, ¿podría pegar más de su código? En cuanto a su código de WebRequest, hay dos cosas en juego aquí:

  1. Sólo está solicitando las cabeceras de la respuesta **, nunca se lee el cuerpo de la respuesta mediante la apertura y lectura (hasta el final) el ResponseStream. Debido a esto, el cliente de WebRequest deja la conexión abierta, esperando que solicite el cuerpo en cualquier momento. Hasta que no lea el cuerpo de la respuesta hasta su finalización (que automáticamente cerrará la transmisión por usted), limpie y cierre la transmisión (o la instancia de WebRequest) o espere a que el GC haga lo suyo, su conexión permanecerá abierta.

  2. usted tiene una cantidad máxima predeterminada de activos conexiones a la misma cantidad de 2. Esto significa que se utiliza encima de sus dos primeras conexiones y luego no disponer de ellos por lo que no se le da a su cliente la oportunidad de completar la la próxima solicitud antes de que llegue a su tiempo de espera (que es de milisegundos, por cierto, por lo que ha establecido en 0,2 segundos - el valor predeterminado debería estar bien).

Si no desea que el cuerpo de la respuesta (o que acaba de cargado o publicado algo y no están esperando una respuesta), basta con cerrar el flujo, o el cliente, que cerrará la Stream para usted.

La forma más fácil de solucionar este problema es asegurarse de que utiliza el uso de bloques de objetos desechables:

for (int i = 0; i < ops1; i++) 
{ 
    Uri myUri = new Uri(site); 
    WebRequest myWebRequest = WebRequest.Create(myUri); 
    //myWebRequest.Timeout = 200; 
    using (WebResponse myWebResponse = myWebRequest.GetResponse()) 
    { 
     // Do what you want with myWebResponse.Headers. 
    } // Your response will be disposed of here 
} 

Otra solución es permitir que 200 conexiones simultáneas con el mismo host. Sin embargo, a menos que usted está pensando en multi-hilo de esta operación por lo que había necesidad de múltiples conexiones concurrentes, esto no es realmente le ayudará a:

ServicePointManager.DefaultConnectionLimit = 200; 

Cuando usted está recibiendo los tiempos de espera del código, lo mejor hacer es intentar recrear ese tiempo de espera fuera de tu código. Si no puede, el problema probablemente recae en su código.Usualmente uso cURL para eso, o simplemente un navegador web si es una simple solicitud GET.

** En realidad, en realidad, está solicitando el primer fragmento de datos de la respuesta, que contiene los encabezados HTTP, y también el inicio del cuerpo. Es por eso que es posible leer información del encabezado HTTP (como Content-Encoding, Set-Cookie, etc.) antes de leer desde la secuencia de salida. A medida que lee la secuencia, se recuperan más datos del servidor. La conexión de WebRequest al servidor se mantiene abierta hasta que llegue al final de esta secuencia (cerrándola de manera efectiva, ya que no se puede buscar), ciérrela manualmente o elimine. There's more about this here.

+0

@Matthew: ¿está seguro de enviar 'HEAD'? No creo que haya visto eso nunca. –

+0

Lo siento, no me refiero a HEAD (HEAD es donde solicita * solo * los encabezados), me refiero a que la respuesta inicial solo contiene los encabezados (que es lo que normalmente obtendría si acaba de enviar una solicitud HEAD). He corregido para corregir mi error. –

+0

@Matthew: de nuevo, ¿qué te hace pensar que la respuesta solo contiene encabezados? ¿Sugiere que haya otro intercambio de paquetes entre el cliente y el servidor en el momento en que se llama al 'GetRequestStream'? –

32

Cierre/elimine su objeto WebResponse.

+3

Buena captura, pero debe mostrarle cómo, o si no lo haré. –

+4

cerrar/desechar no ayuda –

+0

¡Gracias! ¡Funcionó! –

Cuestiones relacionadas