6

Así que mi aplicación está intercambiando solicitudes/respuestas con un servidor (sin problemas), hasta que la conexión a Internet muere durante un par de segundos, luego vuelve. A continuación, un código como el siguiente:Intenta hablar con el servidor cuando Internet no funciona

response = (HttpWebResponse)request.GetResponse();

arrojará una excepción, con un estado como ReceiveFailure, ConnectFailure, KeepAliveFailure etc.

Ahora, es muy importante que si la conexión a Internet se vuelve, yo soy poder seguir comunicándome con el servidor; de lo contrario, tendría que volver a comenzar desde el principio y eso llevará mucho tiempo.

¿Qué le parecería reanudar esta comunicación cuando Internet vuelva?

Por el momento, sigo buscando la posibilidad de comunicarme con el servidor, hasta que sea posible (al menos teóricamente). Mi intento de código es el siguiente:

try 
{ 
    response = (HttpWebResponse)request.GetResponse(); 
} 
catch (WebException ex) 
{ 
    // We have a problem receiving stuff from the server. 
    // We'll keep on trying for a while 
    if (ex.Status == WebExceptionStatus.ReceiveFailure || 
     ex.Status == WebExceptionStatus.ConnectFailure || 
     ex.Status == WebExceptionStatus.KeepAliveFailure) 
    { 
     bool stillNoInternet = true; 

     // keep trying to talk to the server 
     while (stillNoInternet) 
     { 
      try 
      { 
       response = (HttpWebResponse)request.GetResponse(); 
       stillNoInternet = false; 
      } 
      catch 
      { 
       stillNoInternet = true; 
      } 
     } 
    } 
} 

Sin embargo, el problema es que la declaración segundo try-catch mantiene lanzar una excepción, incluso cuando el Internet está de vuelta.

¿Qué estoy haciendo mal? ¿Hay alguna otra manera de arreglar esto?

Gracias!

+0

No es una respuesta a su pregunta, pero si su conexión se interrumpe durante un tiempo prolongado, realmente no tiene una buena manera de matar esto en este momento ... – Paddy

+0

El servidor también tiene un tiempo de espera de 5 minutos, por lo tanto, si la conexión realmente baja por más de 5 minutos, entonces esa es la manera de matarlo. – Andrei

+0

¿por qué no configura un temporizador para probar una conexión cada 10 minutos y luego reinicia lo que estaba haciendo? o tal vez cada vez que hay una falla de conexión, aumente el tiempo de espera en un minuto. –

Respuesta

15

Debe volver a crear la solicitud cada vez, y debe ejecutar los reintentos en un bucle con una espera entre cada reintento. El tiempo de espera debería aumentar progresivamente con cada falla.

E.g.

ExecuteWithRetry (delegate { 
    // retry the whole connection attempt each time 
    HttpWebRequest request = ...; 
    response = request.GetResponse(); 
    ... 
}); 

private void ExecuteWithRetry (Action action) { 
    // Use a maximum count, we don't want to loop forever 
    // Alternativly, you could use a time based limit (eg, try for up to 30 minutes) 
    const int maxRetries = 5; 

    bool done = false; 
    int attempts = 0; 

    while (!done) { 
     attempts++; 
     try { 
      action(); 
      done = true; 
     } catch (WebException ex) { 
      if (!IsRetryable (ex)) { 
       throw; 
      } 

      if (attempts >= maxRetries) { 
       throw; 
      } 

      // Back-off and retry a bit later, don't just repeatedly hammer the connection 
      Thread.Sleep (SleepTime (attempts)); 
     } 
    } 
} 

private int SleepTime (int retryCount) { 
    // I just made these times up, chose correct values depending on your needs. 
    // Progressivly increase the wait time as the number of attempts increase. 
    switch (retryCount) { 
     case 0: return 0; 
     case 1: return 1000; 
     case 2: return 5000; 
     case 3: return 10000; 
     default: return 30000; 
    } 
} 

private bool IsRetryable (WebException ex) { 
    return 
     ex.Status == WebExceptionStatus.ReceiveFailure || 
     ex.Status == WebExceptionStatus.ConnectFailure || 
     ex.Status == WebExceptionStatus.KeepAliveFailure; 
} 
+0

Gracias Chris. Gran solución y código. – Andrei

0

Si todavía lo está haciendo cuando recupera la conexión, entonces supongo que simplemente está devolviendo el mismo resultado nuevamente.

Es posible que desee intentar volver a crear la solicitud de nuevo cada vez, aparte de eso, no veo mucho mal con el código o la lógica. Además del hecho de que estás bloqueando para siempre este hilo. Pero entonces eso podría estar bien si esto es, en sí mismo, un hilo de trabajo.

1

Creo que lo que está tratando de hacer es lo siguiente:

HttpWebResponse RetryGetResponse(HttpWebRequest request) 
{ 
    while (true) 
    { 
     try 
     { 
      return (HttpWebResponse)request.GetResponse(); 
     } 
     catch (WebException ex) 
     { 
      if (ex.Status != WebExceptionStatus.ReceiveFailure && 
       ex.Status != WebExceptionStatus.ConnectFailure && 
       ex.Status != WebExceptionStatus.KeepAliveFailure) 
      { 
       throw; 
      } 
     } 
    } 
} 

Cuando se desea volver a intentar algo en falta a continuación, en lugar de pensar en esto como algo que usted quiere hacer cuando algo falla, piense en ello como un bucle hasta que tenga éxito. (o un error que no desea volver a intentar). Lo anterior continuará reintentando hasta que se devuelva una respuesta o se produzca una excepción diferente.

También sería una buena idea introducir un límite máximo de reintento de algún tipo (por ejemplo, detener el intento una vez transcurrida 1 hora).

Cuestiones relacionadas