6

したがって、私のアプリケーションは、インターネット接続が数秒間停止してから戻ってくるまで、サーバーと要求/応答を交換しています(問題はありません)。次に、次のようなコード:

response = (HttpWebResponse)request.GetResponse();

、などReceiveFailureのステータスで例外をスローします。ConnectFailureKeepAliveFailure

さて、インターネット接続が回復した場合、サーバーとの通信を継続できることが非常に重要です。そうしないと、最初からやり直す必要があり、それには長い時間がかかります。

インターネットが戻ってきたら、どうやってこのコミュニケーションを再開しますか?

現時点では、(少なくとも理論的には)可能になるまで、サーバーとの通信の可能性をチェックし続けています。私のコードの試みは次のようになります:

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;
            }
        }
    }
}

ただし、問題は、インターネットが復旧した場合でも、2番目のtry-catchステートメントが例外をスローし続けることです。

私は何が間違っているのですか?これを修正する別の方法はありますか?

ありがとう!

4

3 に答える 3

17

毎回リクエストを再作成し、各再試行の間に待機してループで再試行を実行する必要があります。待機時間は、失敗するたびに徐々に増加する必要があります。

例えば

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;
}
于 2011-08-05T12:47:12.667 に答える
1

あなたがやろうとしていることはこれだと思います:

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;
            }
        }
    }
}

失敗したときに何かを再試行したい場合は、これを何かが失敗したときにやりたいことと考えるのではなく、成功するまでループすることと考えてください。(または再試行したくない失敗)。上記は、応答が返されるか、別の例外がスローされるまで再試行を続けます。

なんらかの再試行の上限を設定することもお勧めします (たとえば、1 時間後に再試行を停止するなど)。

于 2011-08-05T12:48:14.773 に答える
0

接続が戻ったときにまだそれを実行している場合、私の推測では、同じ結果が再び返されるだけです。

コードやロジックに問題があるとは思わないことを除けば、毎回リクエストを再作成してみてください。あなたがこのスレッドを永遠にブロックしているという事実は別として。しかし、それ自体がワーカー スレッドである場合は問題ありません。

于 2011-08-05T12:32:12.657 に答える