Перейти к основному содержимому

Тайм-аут соединения и тайм-аут чтения для сокетов Java

· 4 мин. чтения

1. Введение

В этом руководстве мы сосредоточимся на исключениях тайм-аута в программировании сокетов 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 и узнали, как с ними обращаться.

Как всегда, код доступен на GitHub .