在 Java 中超时重试连接

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/7312794/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-30 19:30:18  来源:igfitidea点击:

Retry a connection on timeout in Java

java

提问by InsanityOnABun

I have a method (below) that pulls down and returns the source of a webpage as a String. It all works fine and dandy, but when the connection times out, the program throws an exception and exits. Is there a better method to do this that would allow it to try again on timeout, or is there a way to do it within this method?

我有一个方法(如下)可以下拉并以字符串形式返回网页的源。一切正常,但当连接超时时,程序会抛出异常并退出。有没有更好的方法来做到这一点,让它在超时时再次尝试,或者有没有办法在这个方法中做到这一点?

public static String getPage(String theURL) {
    URL url = null;
    try {
        url = new URL(theURL);
    } catch (MalformedURLException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
        exitprint();
    }
    InputStream is = null;
    try {
        is = url.openStream();
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
        exitprint();
    }
    int ptr = 0;
    StringBuffer buffer = new StringBuffer();
    try {
        while ((ptr = is.read()) != -1) {
            buffer.append((char)ptr);
        }
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
        exitprint();
    }

    return buffer.toString();
}

采纳答案by aioobe

Here's a refactoring of your code that should retry the download Ntimes. Haven't tested it though, but it should kick you off in the right direction.

这是您的代码的重构,应该重试下载N时间。虽然还没有测试过,但它应该会让你朝着正确的方向前进。

public static String getPage(String theURL) {

    URL url = null;
    try {
        url = new URL(theURL);
    } catch (MalformedURLException e) {
        e.printStackTrace();
        exitprint();
    }

    for (int i = 0; i < N; i++) {

        try {
            InputStream is = url.openStream();

            int ptr = 0;
            StringBuffer buffer = new StringBuffer();

            while ((ptr = is.read()) != -1)
                buffer.append((char)ptr);

        } catch (IOException e) {
            continue;
        }

        return buffer.toString();
    }

    throw new SomeException("Failed to download after " + N + " attepmts");
}

回答by Kevin

Write a wrapper function around it and allow the connect exception to propogate out. Then you can loop calling your existing function while you receive connect exception upto some max retries.

围绕它编写一个包装函数并允许连接异常传播出去。然后,您可以在收到连接异常时循环调用现有函数,直至达到最大重试次数。

This is better than embedding a for loop in your existing function because it logically separates retry logic from mainline code. And it's easier to read and understand as a result.

这比在现有函数中嵌入 for 循环要好,因为它在逻辑上将重试逻辑与主线代码分开。因此,它更易于阅读和理解。

回答by andronikus

You could put the whole thing in a whileloop:

你可以把整个事情放在一个while循环中:

while (true) {

  try {
    ...
  } catch (IOException e) {
    continue;
  }

  return buffer.toString();
}

The returnstatement will break you out of the loop. You might also want to keep track of the number of attempts and stop after 5-10, for politeness, but that's the basic shape of it.

return语句将使您跳出循环。为了礼貌起见,您可能还想记录尝试次数并在 5-10 次后停止,但这是它的基本形状。

Edit

编辑

The better version, based on comments:

更好的版本,基于评论:

int retries = 10;
for (int i = 0 ; i < retries ; i++) {

  try {
    ...
  } catch (IOException e) {
    continue;
  }

  return buffer.toString();
}

回答by bpgergo

Instead of

代替

try {
    is = url.openStream();
} catch (IOException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
    exitprint();
}

you can try set longer timeout and you can still handle timeout exception by catching it

您可以尝试设置更长的超时时间,您仍然可以通过捕获来处理超时异常

try {
    URLConnection con= url.openConnection();
    con.setConnectTimeout(5000); 
    con.setReadTimeout(50000);
    BufferedReader in = new BufferedReader(
        new InputStreamReader(con.getInputStream()));
    String inputLine;
    while ((inputLine = in.readLine()) != null) 
        System.out.println(inputLine);
    in.close();
} catch (SocketTimeoutException e) {
    //here you can still handle timeout like try again under certain conditions
}

回答by yegor256

I think AOP and Java annotations is a good option. I would recommend to use a read-made mechanism from jcabi-aspects:

我认为 AOP 和 Java 注释是一个不错的选择。我会建议使用jcabi-aspects 中的一种只读机制:

@RetryOnFailure(attempts = 2, delay = 10)
public String load(URL url) {
  return url.openConnection().getContent();
}