«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) и установим параметр тайм-аута: вызов метода возвращает исключение SocketTimeoutException:
Socket socket = new Socket();
SocketAddress socketAddress = new InetSocketAddress(host, port);
socket.connect(socketAddress, 30000);
На стороне сервера мы будем использовать метод setSoTimeout(int timeout) для установки значения времени ожидания. Значение тайм-аута определяет, как долго метод ServerSocket.accept() будет блокироваться:
Exception in thread "main" java.net.SocketTimeoutException: Connect timed out
Точно так же единица тайм-аута должна быть в миллисекундах и должна быть больше 0. Если тайм-аут истекает до возврата метода, он выдаст Исключение SocketTimeoutException.
ServerSocket serverSocket = new new ServerSocket(port);
serverSocket.setSoTimeout(40000);
Иногда брандмауэры блокируют определенные порты из соображений безопасности. В результате, когда клиент пытается установить соединение с сервером, может возникнуть ошибка «время ожидания соединения истекло». Поэтому мы должны проверить настройки брандмауэра, чтобы увидеть, не блокирует ли он порт, прежде чем привязывать его к службе.
4. Время чтения истекло
4.1. Что такое «Время чтения истекло»?
«Вызов метода read() в InputStream блокируется до тех пор, пока он не закончит чтение байтов данных из сокета. Операция ожидает, пока не прочитает хотя бы один байт данных из сокета. Однако, если метод ничего не возвращает по истечении неопределенного времени, он генерирует исключение InterrupedIOException с сообщением об ошибке «Время чтения истекло»:
4.2. Почему это происходит?
java.net.SocketTimeoutException: Read timed out
Со стороны клиента ошибка «чтение истекло» возникает, если серверу требуется больше времени для ответа и отправки информации. Это может быть связано с медленным подключением к Интернету или хост может быть не в сети.
Со стороны сервера это происходит, когда серверу требуется много времени для чтения данных по сравнению с заданным временем ожидания.
4.3. Как с этим справиться?
Как для TCP-клиента, так и для сервера, мы можем указать количество времени, в течение которого метод socketInputStream.read() блокируется с помощью метода setSoTimeout(int timeout):
Однако, если тайм-аут истекает до возврата метода , программа выдаст исключение SocketTimeoutException.
Socket socket = new Socket(host, port);
socket.setSoTimeout(30000);
5. Заключение
В этой статье мы рассмотрели исключения времени ожидания в программировании сокетов Java и узнали, как с ними обращаться.
Как всегда, код доступен на GitHub.
«