Тайм-аут HTTPUrlConnection Java не работает

Я написал программу, которая открывает httpurlconnection на веб-сайт через случайные прокси. Мое httpurlconnection называется conn. Теперь я знаю, что некоторые из этих прокси-серверов могут быть слишком медленными, поэтому я установил таймаут соединения на 40000 миллисекунд с помощью conn.setConnectTimeout(40000) и conn.setReadTimeout(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 и получаю следующий вывод:


Сообщение: Время ожидания подключения: connect MyTimeout: 40000 Фактическое время прошло: 21012

Сообщение: Время ожидания подключения: connect MyTimeout: 40000 Фактическое время прошло: 21016

Сообщение: Время ожидания подключения: connect MyTimeout: 40000 Фактическое время прошло: 21010

Сообщение: Время ожидания подключения: connect MyTimeout: 40000 Фактическое время прошло: 21009


Итак, мой вопрос: я установил тайм-аут до 40000 миллисекунд, но я получаю ответ "Время ожидания соединения" после примерно 21000 миллисекунд, знает ли кто-нибудь, почему это?

EDIT: im, используя окна 7, и теперь я добавил e.printStackTrace() в блок catch, как сказано в комментариях. Спасибо. теперь результат (пример):

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

Ответ 1

Посмотрите на полученное вами исключение:
Самая большая подсказка: вы получаете 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 мы получаем a java.net.SocketTimeoutException, потому что процесс java способен установить соединение (на порт прокси), но не получает никаких данных для чтения, поскольку номер порта целевого хоста недействителен.
  • В случае №2, №5 мы получаем java.net.ConnectException, потому что порт, при котором java-процесс пытается записать/прочитать, недействителен
  • Значение тайм-аута соединения не подходит для случаев, когда процесс не прослушивает порт, с которым пытается подключиться Java-процесс. Вот почему вы получаете ConnectException до истечения времени ожидания

Message: Connection refused: connect MyTimeout:10000 Actual time passed: 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 и пометить прокси как недействительный /down

Ответ 2

По моему опыту, HttpUrlConnection не будет таймаутом во время разрешения имени. Если ваше устройство кэширует целевой адрес, то он будет тайм-аут правильно.

В целях тестирования используйте свой IP-адрес в своем коде.

Это обычно происходит со мной на мобильных устройствах.