Java HTTPUrlConnection超时不起作用。

10

我编写了一个程序,通过随机代理打开一个网站的httpurlconnection。我的httpurlconnection被称为conn。现在我知道,有些代理可能太慢了,所以我使用conn.setConnectTimeout(40000)conn.setReadTimeout(40000)将连接的超时时间设置为40000毫秒。

这样做之后,我得到了这段代码:

long diff = 0;
    long starttime = 0;
    long endtime = 0;

    try
    {
        starttime = System.currentTimeMillis();
        conn.connect();

        endtime = System.currentTimeMillis();

        diff = endtime - starttime;

        if (endtime <= starttime + conn.getConnectTimeout())
        {
            //Trying to read sourecode
            InputStreamReader isrConn = new InputStreamReader(conn.getInputStream());
            BufferedReader brConn = new BufferedReader(isrConn);

            line = brConn.readLine();

            while (line != null)
            {

                response += line + "\t";
                try
                {
                    line = brConn.readLine();
                } catch (IOException e)
                {
                    printError("Reading sourcecode failed.");
                }

            }
        }
        else
        {
            response = "blabla.";
        }




    // If conn.connect failed   
    } catch (IOException e)
    {
        endtime = System.currentTimeMillis();
        diff = endtime - starttime;

        response = "Message: "+e.getMessage() +" MyTimeout:"+ conn.getConnectTimeout() +" Actual time passed:  "+ diff;
               e.printStackTrace();


    }

有很多原因可能导致连接失败,所以在许多情况下,我会进入最后的catch块并得到以下输出:

Message: Connection timed out: connect MyTimeout:40000 Actual time passed: 21012

Message: Connection timed out: connect MyTimeout:40000 Actual time passed: 21016

Message: Connection timed out: connect MyTimeout:40000 Actual time passed: 21010

Message: Connection timed out: connect MyTimeout:40000 Actual time passed: 21009


所以我的问题是:我已将超时设置为40000毫秒,但在约21000毫秒后我收到了“连接超时”的响应,请问您知道这是为什么吗?

编辑:我正在使用Windows 7,并且现在根据评论中的建议在catch块中添加了e.printStackTrace()。谢谢到目前为止提供的帮助。现在的输出结果如下(示例):

java.net.ConnectException: Connection timed out: connect
    at java.net.DualStackPlainSocketImpl.waitForConnect(Native Method)
    at java.net.DualStackPlainSocketImpl.socketConnect(Unknown Source)
    at java.net.AbstractPlainSocketImpl.doConnect(Unknown Source)
    at java.net.AbstractPlainSocketImpl.connectToAddress(Unknown Source)
    at java.net.AbstractPlainSocketImpl.connect(Unknown Source)
    at java.net.PlainSocketImpl.connect(Unknown Source)
    at java.net.Socket.connect(Unknown Source)
    at sun.net.NetworkClient.doConnect(Unknown Source)
    at sun.net.www.http.HttpClient.openServer(Unknown Source)
    at sun.net.www.http.HttpClient$1.run(Unknown Source)
    at sun.net.www.http.HttpClient$1.run(Unknown Source)
    at java.security.AccessController.doPrivileged(Native Method)
    at sun.net.www.http.HttpClient.privilegedOpenServer(Unknown Source)
    at sun.net.www.http.HttpClient.openServer(Unknown Source)
    at sun.net.www.http.HttpClient.<init>(Unknown Source)
    at sun.net.www.http.HttpClient.New(Unknown Source)
    at sun.net.www.http.HttpClient.New(Unknown Source)
    at sun.net.www.protocol.http.HttpURLConnection.getNewHttpClient(Unknown Source)
    at sun.net.www.protocol.http.HttpURLConnection.plainConnect(Unknown Source)
    at sun.net.www.protocol.http.HttpURLConnection.connect(Unknown Source)
    at TestThread.getSourcePage(TestThread.java:361)
    at TestThread.aChecker(TestThread.java:216)
    at TestThread.getNextProxy(TestThread.java:169)
    at TestThread.getNextC(TestThread.java:157)
    at TestThread.aChecker(TestThread.java:273)
    at TestThread.getNextProxy(TestThread.java:169)
    at TestThread.aChecker(TestThread.java:295)
    at TestThread.getNextProxy(TestThread.java:169)
    at TestThread.getNextC(TestThread.java:157)
    at TestThread.run(TestThread.java:103)
    at java.lang.Thread.run(Unknown Source)

Message: Connection timed out: connect MyTimeout:40000 Actual time passed:  21015

3
请输出并发布实际的堆栈跟踪信息,而不是您自己的消息。 - Brian Roach
1
这可能与操作系统有关,请指定是哪个操作系统。 - Oleg Mikheev
请按照Brian Roach的建议,在catch块中发布e.printStackTrace()的输出。 - Chris Snow
5
21秒是因为Windows系统的设置:http://superuser.com/questions/339959/how-to-set-tcp-ip-abort-interval-or-timeout-in-windows-xp (这些数值在Windows 7中也是相同的)。请注意,通常当您设置连接超时时,这是因为您希望在比系统默认时间更短的时间内超时。 - Brian Roach
根据情况(即您是否控制应用程序运行的环境),您将能够在操作系统中重新配置超时。 - Tim B
显示剩余6条评论
2个回答

11

看看你收到的异常:
最大的线索:你得到了java.net.ConnectException 根据javadoc,java.net.ConnectException表示远程拒绝连接的原因是没有进程正在侦听该端口。

public class ConnectException
extends SocketException

Signals that an error occurred while attempting to connect a socket to a remote address and port. 
Typically, the connection was refused remotely (e.g., no process is listening on the remote 
address/port)

你在HttpUrlConnection中配置的内容:
连接的超时时间(假设远程端口接受连接). 如果连接超时,你会得到一个java.net.SocketTimeoutException而不是java.net.ConnectException

那么,什么导致了java.net.ConnectException?
我尝试了以下测试用例:

   +------------+------------+----------------+------------------+---------------------------------+ 
   | Valid Host | Valid Port | Valid Proxy IP | Valid Proxy Port | Exception                       | 
   +------------+------------+----------------+------------------+---------------------------------+ 
#1 | yes        | yes        | -NA-           | -NA-             | -- none --                      |
#2 | yes        | no         | -NA-           | -NA-             | java.net.ConnectException       |
   +------------+------------+----------------+------------------+---------------------------------+ 
#3 | yes        | yes        | yes            | yes              | -- none --                      |
#4 | yes        | no         | yes            | yes              | java.net.SocketTimeoutException |
#5 | yes        | yes        | yes            | no               | java.net.ConnectException       |
   +------------+------------+----------------+------------------+---------------------------------+ 
  • 情况#1和#3是顺利进行的,其中所有配置都正确
  • 在情况#4中,我们遇到了java.net.SocketTimeoutException,因为Java进程能够建立连接(到代理端口),但无法获取任何数据以读取目标主机的端口号是无效的
  • 在情况#2和#5中,我们得到java.net.ConnectException,因为Java进程尝试写入/读取的端口无效
  • 连接超时值不适用于Java进程尝试连接的端口上没有任何进程侦听的情况。这就是为什么在超时到期之前会出现ConnectException的原因

消息:Connection refused: connect MyTimeout:10000 实际经过的时间:6549 java.net.ConnectException:Connection refused:connect at java.net.DualStackPlainSocketImpl.waitForConnect(Native Method) at java.net.DualStackPlainSocketImpl.socketConnect(DualStackPlainSocketImpl.java:85) .... ....

结论:

  • 您尝试连接的某些代理可能已经宕机。因此Java进程抛出了java.net.ConnectException
  • 最好捕获java.net.ConnectException并将代理标记为无效/宕机

6

根据我的经验,HttpUrlConnection在名称解析期间不会超时。如果您的设备已缓存目标地址,则它将正确超时。

为了测试,请在代码中使用您的IP地址。

这通常发生在移动设备上。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接