- Тайм-аут соединения и тайм-аут чтения для сокетов Java
- 2. Сокеты Java и тайм-ауты
- 3. Время ожидания соединения истекло
- 3.1. Что такое «время ожидания соединения истекло»?
- 3.2. Почему это происходит?
- 3.3. Как с этим справиться?
- 4. Тайм-аут чтения
- 4.1. Что такое «Время чтения истекло»?
- 4.2. Почему это происходит?
- 4.3. Как с этим справиться?
- 5. Вывод
- Timeouts and how to handline in Java
- Connection timeout
- Socket timeout
- Read timeout
- Write timeout
- Apache Camel
- Rest Template
- WebClient
- Summary
- Connection Timeout In Java HTTPClient, RestTemplate and URLConnection
- HttpURLConnection Timeout Example
- Apache HttpClient Timeout example
- Spring RestTemplate Timeout Example
Тайм-аут соединения и тайм-аут чтения для сокетов Java
В этом руководстве мы сосредоточимся на исключениях тайм-аута в программировании сокетов Java . Наша цель — понять, почему возникают эти исключения и как с ними работать.
2. Сокеты Java и тайм-ауты
Сокет — это конечная точка логической связи между двумя компьютерными приложениями . Другими словами, это логический интерфейс, который приложения используют для отправки и получения данных по сети.
В общем случае сокет представляет собой комбинацию IP-адреса и номера порта . Каждому сокету назначается определенный номер порта, который используется для идентификации службы.
Службы на основе соединений используют сокеты потока на основе TCP . По этой причине Java предоставляет класс java.net.Socket для программирования на стороне клиента . С другой стороны, в программировании TCP/IP на стороне сервера используется класс java.net.ServerSocket .
Другим типом сокета является сокет дейтаграмм на основе UDP, который используется для служб без установления соединения. Java предоставляет java.net.DatagramSocket для операций UDP . Однако в этом руководстве мы сосредоточимся на сокетах TCP/IP.
3. Время ожидания соединения истекло
3.1. Что такое «время ожидания соединения истекло»?
Для установления соединения с сервером со стороны клиента вызывается конструктор сокета , который создает экземпляр объекта сокета. Конструктор принимает адрес удаленного хоста и номер порта в качестве входных параметров . После этого он пытается установить соединение с удаленным хостом на основе заданных параметров.
Операция блокирует все остальные процессы до тех пор, пока не будет установлено успешное соединение . Однако, если соединение не установлено через определенное время, программа выдает исключение ConnectionException с сообщением «Время ожидания соединения истекло»:
java.net.ConnectException: Connection timed out: connect
Со стороны сервера класс ServerSocket постоянно прослушивает входящие запросы на подключение. Когда ServerSocket получает запрос на подключение, он вызывает метод accept() для создания экземпляра нового объекта сокета . Точно так же этот метод также блокируется до тех пор, пока не будет установлено успешное соединение с удаленным клиентом.
В случае, если рукопожатия TCP не завершены, соединение остается безуспешным. Следовательно, программа выдает исключение IOException , указывающее на ошибку при установлении нового соединения .
3.2. Почему это происходит?
Причин ошибки тайм-аута соединения может быть несколько:
- Ни одна служба не прослушивает данный порт на удаленном хосте
- Удаленный хост не принимает никаких соединений
- Удаленный хост недоступен
- Медленное подключение к интернету
- Нет пути переадресации на удаленный хост
3.3. Как с этим справиться?
Время блокировки не ограничено, и программист может предварительно установить параметр тайм-аута как для клиентских, так и для серверных операций . Для клиентской стороны мы сначала создадим пустой сокет. После этого воспользуемся методом connect(SocketAddress endpoint, int timeout) и установим параметр timeout:
Socket socket = new Socket(); SocketAddress socketAddress = new InetSocketAddress(host, port); socket.connect(socketAddress, 30000);
Единица тайм-аута указана в миллисекундах и должна быть больше 0. Однако, если тайм-аут истечет до того, как вызов метода вернется, он вызовет исключение SocketTimeoutException :
Exception in thread "main" java.net.SocketTimeoutException: Connect timed out
На стороне сервера мы будем использовать метод setSoTimeout (int timeout) для установки значения времени ожидания. Значение тайм -аута определяет, как долго будет блокироваться метод ServerSocket.accept() :
ServerSocket serverSocket = new new ServerSocket(port); serverSocket.setSoTimeout(40000);
Точно так же единица времени ожидания должна быть в миллисекундах и должна быть больше 0. Если время ожидания истечет до возврата метода, он вызовет SocketTimeoutException .
Иногда брандмауэры блокируют определенные порты из соображений безопасности . В результате может возникнуть ошибка «время ожидания соединения истекло», когда клиент пытается установить соединение с сервером. Поэтому мы должны проверить настройки брандмауэра, чтобы увидеть, не блокирует ли он порт, прежде чем привязывать его к службе.
4. Тайм-аут чтения
4.1. Что такое «Время чтения истекло»?
Вызов метода read() в InputStream блокируется до тех пор, пока он не закончит чтение байтов данных из сокета. Операция ожидает, пока не прочитает хотя бы один байт данных из сокета. Однако, если метод ничего не возвращает по истечении неопределенного времени, он выдает InterrupedIOException с сообщением об ошибке «Время ожидания чтения истекло» :
java.net.SocketTimeoutException: Read timed out
4.2. Почему это происходит?
Со стороны клиента ошибка «чтение истекло» возникает, если серверу требуется больше времени для ответа и отправки информации . Это может быть связано с медленным подключением к Интернету или хост может быть не в сети.
Со стороны сервера это происходит, когда серверу требуется много времени для чтения данных по сравнению с предустановленным тайм-аутом .
4.3. Как с этим справиться?
Как для TCP-клиента, так и для сервера мы можем указать количество времени, в течение которого « метод socketInputStream.read() блокирует « метод setSoTimeout(int timeout) :
Socket socket = new Socket(host, port); socket.setSoTimeout(30000);
Однако, если время ожидания истечет до возврата метода, программа выдаст SocketTimeoutException .
5. Вывод
В этой статье мы рассмотрели исключения тайм-аута в программировании сокетов Java и узнали, как с ними обращаться.
Timeouts and how to handline in Java
In this article we will try to cover why it’s important to define timeouts for out bound rest calls. Before configuring any timeout let’s understand below some common exceptions for http outbound calls,
Connection timeout
maximum time to wait for the other side to answer «yes, I’m here, let’s talk» when creating a new connection, (ConnectTimeout eventually calls socket.connect(address, timeout), If the connection is not established within the ConnectTimeout specified by you or the library you are using then, you get an error ‘connect timedout
Socket timeout
Is the timeout for waiting for data or, put differently, a maximum period inactivity between two consecutive data packets
Read timeout
Read timeout can happen when there is successful connection established between client and the server and there is an inactivity between data packets while waiting for the server response.
Write timeout
Similar to Read timeout, write timeout can happen when there is successful connection established between client and server, and there is inactivity between data packets while sending the request to the server. The important topic to remember here is that based on the choice of library we use for outbound calls it’s very important that we configure the properties to handle the above mentioned one’s and handle the exception gracefully.
Apache Camel
If we are using Apache Camel ‘http’ component to make the outbound calls then we can configure these properties in following ways, please note that if we don’t define this properties the default values is -1! means connection will never timeout and can have advert effect on the application performance overall. camel.property
http.urlProxy = http4://ThirdPartyServers?throwExceptionOnFailure=false&httpClient.socketTimeout=$&httpClient.connectTimeout=$
@Override public void configure() throws Exception configureTimeout(); > private void configureTimeout() HttpComponent httpComponent = getContext().getComponent("http4", HttpComponent.class); httpComponent.setConnectionTimeToLive(VALUE_IN_MILI);// for closing the idle connection - in milliseconds httpComponent.setSocketTimeout(VALUE_IN_MILI); //socket timeout - in milliseconds httpComponent.setConnectTimeout(VALUE_IN_MILI); // connection timeout - in milliseconds*/ >
Rest Template
final RequestConfig requestConfig = RequestConfig.custom() .setConnectionRequestTimeout(VALUE_IN_MILI) .setConnectTimeout(VALUE_IN_MILI) .setSocketTimeout(VALUE_IN_MILIs) .build(); final HttpClient httpClient = HttpClients.custom() .setConnectionTimeToLive(VALUE_IN_MILI, SECONDS) .setRetryHandler((IOException exception, int executionCount, HttpContext context) -> return executionCount 3; >) .setServiceUnavailableRetryStrategy(new DefaultServiceUnavailableRetryStrategy(3, 1)) .setDefaultRequestConfig(requestConfig) .build(); final RestTemplate restTemplate = new RestTemplate(new HttpComponentsClientHttpRequestFactory(httpClient));
WebClient
public WebClient getWebClient() HttpClient httpClient = HttpClient.create() .tcpConfiguration(client -> client.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, VALUE_IN_MILI) .doOnConnected(conn -> conn .addHandlerLast(new ReadTimeoutHandler(rest.timeout.millis)) .addHandlerLast(new WriteTimeoutHandler(rest.timeout.millis)))); ClientHttpConnector connector = new ReactorClientHttpConnector(httpClient.wiretap(true)); return WebClient.builder() .baseUrl("http://localhost:3000") .clientConnector(connector) .defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE) .build(); >
Summary
All in all it’s very important to configure these values i.e. connection timeout, read timeout, socket timeout etc so as to terminate the connections after waiting for a specific amount of time rather keeping the connection open indefinitely which can bring issues to overall application performance and stability.
Connection Timeout In Java HTTPClient, RestTemplate and URLConnection
Connection timeout is the time for which an HTTP client or Socket client waits, if the server doesn’t respond in that time or not found then the client closes the connection. HTTP also uses sockets internally. Connection timeout is different from the Connection Request timeout or connection read timeout.
In many situations, the client doesn’t want to wait for a long time in that case a connection time out or Request connection timeout or both can be set.
Here are an example of the most used Java HTTP clients.
HttpURLConnection Timeout Example
Here is an example of setting connection time out and connection read time out.
try < final URL url = new URL("http://134.234.3.17"); final HttpURLConnection urlConn = (HttpURLConnection) url.openConnection(); HttpURLConnection.setFollowRedirects(false); // Sets a specified timeout value, in milliseconds, to be used when opening a // communications link to the resource reference by this URLConnection. If the // timeout expires before the connection can be established, // a java.net.SocketTimeoutException is raised. A timeout of zero is interpreted // as an infinite timeout. // Here 5 second time out is set urlConn.setConnectTimeout(5 * 1000); urlConn.setReadTimeout(5 * 1000); urlConn.setRequestMethod("GET"); urlConn.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.1.2) Gecko/20090729 Firefox/3.5.2 (.NET CLR 3.5.30729)"); urlConn.connect(); >catch (final Exception e)
Apache HttpClient Timeout example
Here is an example of setting Connection time out and Request Connection time out. Not Connection Read timeout is the same as Request connection timeout.
try < final int timeout = 5000;// 5 seconds final RequestConfig config = RequestConfig.custom().setConnectTimeout(timeout) .setConnectionRequestTimeout(timeout).build(); final HttpClientBuilder builder = HttpClientBuilder.create(); builder.setDefaultRequestConfig(config); final HttpClient client = builder.build(); final HttpGet request = new HttpGet("http://134.234.3.17"); // GET Request final HttpResponse response = client.execute(request); >catch (final Exception e)
Spring RestTemplate Timeout Example
Here is an example of the RestTemplate timeouts. It will set 5 seconds connection timeout and 5 seconds of reading time out.
RestTemplate template = new RestTemplate(); HttpComponentsClientHttpRequestFactory rf = (HttpComponentsClientHttpRequestFactory) template.getRequestFactory(); rf.setReadTimeout(5 * 1000); rf.setConnectTimeout(5 * 1000);
You can define it as given below in Spring config
@Bean public RestTemplate restTemplate(RestTemplateBuilder restTemplateBuilder)