Тайм-аут 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-адрес в своем коде.
Это обычно происходит со мной на мобильных устройствах.