Как создать сетевое приложение на Java (с изображениями)

Оглавление:

Как создать сетевое приложение на Java (с изображениями)
Как создать сетевое приложение на Java (с изображениями)

Видео: Как создать сетевое приложение на Java (с изображениями)

Видео: Как создать сетевое приложение на Java (с изображениями)
Видео: Как сделать скриншот на телефоне Samsung, Asus, Xiaomi? 2024, Апрель
Anonim

Написание кода, который выполняется на определенном устройстве, очень приятно. Но написание кода, который выполняется на нескольких устройствах, взаимодействующих друг с другом, просто жизнеутверждает. В этой статье вы узнаете, как подключаться и обмениваться сообщениями по сети с использованием протокола управления передачей (TCP).

В этой статье вы настроите приложение, которое будет подключать ваш компьютер к самому себе и, по сути, сводить его с ума - разговаривать сам с собой. Вы также узнаете разницу между двумя наиболее широко используемыми потоками для работы в сети на Java и как они работают.

Потоки данных и объектов

Прежде чем погрузиться в код, необходимо выделить разницу между двумя потоками, используемыми в статье.

Потоки данных

Потоки данных обрабатывают примитивные типы данных и строки. Данные, отправляемые через потоки данных, необходимо сериализовать и десериализовать вручную, что затрудняет передачу сложных данных. Но потоки данных могут связываться с серверами и клиентами, написанными на других языках, кроме Java. Необработанные потоки похожи на потоки данных в этом аспекте, но потоки данных обеспечивают форматирование данных независимо от платформы, что выгодно, поскольку обе стороны смогут читать отправленные данные.

Потоки объектов

Потоки объектов обрабатывают примитивные типы данных и объекты, реализующие

Сериализуемый

интерфейс. Данные, отправляемые через потоки объектов, автоматически сериализуются и десериализуются, что упрощает передачу сложных данных. Но потоки объектов могут взаимодействовать только с серверами и клиентами, написанными на Java. Также,

ObjectOutputStream

при инициализации отправляет заголовок в

InputStream

другой стороны, которая при инициализации блокирует выполнение до тех пор, пока не будет получен заголовок.

Шаги

Создайте сетевое приложение на Java Step1
Создайте сетевое приложение на Java Step1

Шаг 1. Создайте класс

Создайте класс и назовите его как хотите. В этой статье он будет называться

NetworkAppExample

общедоступный класс NetworkAppExample {}

Создайте сетевое приложение на Java Step2
Создайте сетевое приложение на Java Step2

Шаг 2. Создайте основной метод

Создайте основной метод и объявите, что он может вызывать исключения из

Исключение

тип и любой его подкласс - все исключения. Это считается плохой практикой, но приемлемо для примеров barebone-систем.

открытый класс NetworkAppExample {public static void main (String args) выдает исключение {}}

Создание сетевого приложения на Java Step3
Создание сетевого приложения на Java Step3

Шаг 3. Объявите адрес сервера

В этом примере будет использоваться адрес локального хоста и произвольный номер порта. Номер порта должен быть в диапазоне от 0 до 65535 (включительно). Однако номера портов, которых следует избегать, находятся в диапазоне от 0 до 1023 (включительно), поскольку они являются зарезервированными системными портами.

открытый класс NetworkAppExample {public static void main (String args) выдает исключение {String host = "localhost"; int port = 10430; }}

Создайте сетевое приложение на Java Step4
Создайте сетевое приложение на Java Step4

Шаг 4. Создайте сервер

Сервер привязан к адресу и порту и прослушивает входящие соединения. В Java

ServerSocket

представляет конечную точку на стороне сервера, и ее функция - прием новых подключений.

ServerSocket

не имеет потоков для чтения и отправки данных, потому что не представляет собой соединение между сервером и клиентом.

import java.net. InetAddress; import java.net. ServerSocket; открытый класс NetworkAppExample {public static void main (String args) выдает исключение {String host = "localhost"; int port = 10430; ServerSocket server = новый ServerSocket (порт, 50, InetAddress.getByName (хост)); }}

Создайте сетевое приложение на Java Step5
Создайте сетевое приложение на Java Step5

Шаг 5. Запуск сервера логов

Для ведения журнала выведите на консоль информацию о том, что сервер запущен.

import java.net. InetAddress; import java.net. ServerSocket; открытый класс NetworkAppExample {public static void main (String args) выдает исключение {String host = "localhost"; int port = 10430; ServerSocket server = новый ServerSocket (порт, 50, InetAddress.getByName (хост)); System.out.println ("Сервер запущен."); }}

Создание сетевого приложения на Java Step6
Создание сетевого приложения на Java Step6

Шаг 6. Создайте клиента

Клиент привязан к адресу и порту сервера и прослушивает пакеты (сообщения) после установления соединения. В Java

Разъем

представляет либо конечную точку на стороне клиента, подключенную к серверу, либо соединение (от сервера) к клиенту, и используется для связи со стороной на другом конце.

import java.net. InetAddress; import java.net. ServerSocket; import java.net. Socket; открытый класс NetworkAppExample {public static void main (String args) выдает исключение {String host = "localhost"; int port = 10430; ServerSocket server = новый ServerSocket (порт, 50, InetAddress.getByName (хост)); System.out.println ("Сервер запущен."); Клиент сокета = новый сокет (хост, порт); }}

Создайте сетевое приложение на Java Step7
Создайте сетевое приложение на Java Step7

Шаг 7. Зарегистрируйте попытку подключения

Для ведения журнала выведите на консоль информацию о попытке подключения.

import java.net. InetAddress; import java.net. ServerSocket; import java.net. Socket; открытый класс NetworkAppExample {public static void main (String args) выдает исключение {String host = "localhost"; int port = 10430; ServerSocket server = новый ServerSocket (порт, 50, InetAddress.getByName (хост)); System.out.println ("Сервер запущен."); Клиент сокета = новый сокет (хост, порт); System.out.println («Подключение к серверу…»); }}

Создайте сетевое приложение на Java Step8
Создайте сетевое приложение на Java Step8

Шаг 8. Установите соединение

Клиенты никогда не будут подключаться, если сервер не прослушивает и не принимает, другими словами, не устанавливает соединения. В Java соединения устанавливаются с использованием

принимать()

метод

ServerSocket

класс. Метод будет блокировать выполнение до тех пор, пока не подключится клиент.

import java.net. InetAddress; import java.net. ServerSocket; import java.net. Socket; открытый класс NetworkAppExample {public static void main (String args) выдает исключение {String host = "localhost"; int port = 10430; ServerSocket server = новый ServerSocket (порт, 50, InetAddress.getByName (хост)); System.out.println ("Сервер запущен."); Клиент сокета = новый сокет (хост, порт); System.out.println («Подключение к серверу…»); Соединение сокета = server.accept (); }}

Создайте сетевое приложение на Java Step9
Создайте сетевое приложение на Java Step9

Шаг 9. Зарегистрируйте установленное соединение

Для ведения журнала выведите на консоль информацию о том, что соединение между сервером и клиентом установлено.

import java.net. InetAddress; import java.net. ServerSocket; import java.net. Socket; открытый класс NetworkAppExample {public static void main (String args) выдает исключение {String host = "localhost"; int port = 10430; ServerSocket server = новый ServerSocket (порт, 50, InetAddress.getByName (хост)); System.out.println ("Сервер запущен."); Клиент сокета = новый сокет (хост, порт); System.out.println («Подключение к серверу…»); Соединение сокета = server.accept (); System.out.println ("Соединение установлено."); }}

Создайте сетевое приложение на Java Step10
Создайте сетевое приложение на Java Step10

Шаг 10. Подготовьте коммуникационные потоки

Связь осуществляется через потоки, и в этом приложении необработанные потоки (соединения от) сервера (к клиенту) и клиента должны быть связаны либо с потоками данных, либо с потоками объектов. Помните, что обе стороны должны использовать один и тот же тип потока.

  • Потоки данных

    import java.io. DataInputStream; import java.io. DataOutputStream; import java.net. InetAddress; import java.net. ServerSocket; import java.net. Socket; открытый класс NetworkAppExample {public static void main (String args) выдает исключение {String host = "localhost"; int port = 10430; ServerSocket server = новый ServerSocket (порт, 50, InetAddress.getByName (хост)); System.out.println ("Сервер запущен."); Клиент сокета = новый сокет (хост, порт); System.out.println («Подключение к серверу…»); Соединение сокета = server.accept (); System.out.println («Соединение установлено.»); DataOutputStream clientOut = новый DataOutputStream (client.getOutputStream ()); DataInputStream clientIn = новый DataInputStream (client.getInputStream ()); DataOutputStream serverOut = новый DataOutputStream (connection.getOutputStream ()); DataInputStream serverIn = новый DataInputStream (connection.getInputStream ()); }}

  • Потоки объектов

    При использовании нескольких потоков объектов входные потоки должны быть инициализированы в том же порядке, что и выходные потоки, потому что

    ObjectOutputStream

    отправляет заголовок другой стороне и

    ObjectInputStream

    блокирует выполнение до тех пор, пока не прочитает заголовок.

    import java.io. ObjectInputStream; import java.io. ObjectOutputStream; import java.net. InetAddress; import java.net. ServerSocket; import java.net. Socket; открытый класс NetworkAppExample {public static void main (String args) выдает исключение {String host = "localhost"; int port = 10430; ServerSocket server = новый ServerSocket (порт, 50, InetAddress.getByName (хост)); System.out.println ("Сервер запущен."); Клиент сокета = новый сокет (хост, порт); System.out.println («Подключение к серверу…»); Соединение сокета = server.accept (); System.out.println ("Соединение установлено."); ObjectOutputStream clientOut = новый ObjectOutputStream (client.getOutputStream ()); ObjectOutputStream serverOut = новый ObjectOutputStream (connection.getOutputStream ()); ObjectInputStream clientIn = новый ObjectInputStream (client.getInputStream ()); ObjectInputStream serverIn = новый ObjectInputStream (connection.getInputStream ()); }}

    Порядок, указанный в приведенном выше коде, может быть проще запомнить - сначала инициализируйте потоки вывода, затем потоки ввода в том же порядке. Однако другой порядок инициализации объектных потоков следующий:

    ObjectOutputStream clientOut = новый ObjectOutputStream (client.getOutputStream ()); ObjectInputStream serverIn = новый ObjectInputStream (connection.getInputStream ()); ObjectOutputStream serverOut = новый ObjectOutputStream (connection.getOutputStream ()); ObjectInputStream clientIn = новый ObjectInputStream (client.getInputStream ());

Создайте сетевое приложение на Java Step11
Создайте сетевое приложение на Java Step11

Шаг 11. Зарегистрируйте, что связь готова

Для ведения журнала выведите на консоль сообщение о том, что связь установлена.

// код пропущен import java.net. InetAddress; import java.net. ServerSocket; import java.net. Socket; открытый класс NetworkAppExample {public static void main (String args) выдает исключение {String host = "localhost"; int port = 10430; ServerSocket server = новый ServerSocket (порт, 50, InetAddress.getByName (хост)); System.out.println ("Сервер запущен."); Клиент сокета = новый сокет (хост, порт); System.out.println («Подключение к серверу…»); Соединение сокета = server.accept (); System.out.println ("Соединение установлено."); // код пропущен System.out.println ("Связь готова."); }}

Создайте сетевое приложение на Java Step12
Создайте сетевое приложение на Java Step12

Шаг 12. Создайте сообщение

В этом приложении

Привет, мир

текст будет отправлен на сервер либо как

байт

или

Нить

. Объявите переменную типа, который зависит от используемого потока. Использовать

байт

для потоков данных и

Нить

для объектных потоков.

  • Потоки данных

    Используя потоки данных, сериализация осуществляется путем преобразования объектов в примитивные типы данных или

    Нить

    . В этом случае,

    Нить

    конвертируется в

    байт

    вместо написания с использованием

    writeBytes ()

    чтобы показать, как это будет сделано с другими объектами, такими как изображения или другие файлы.

    import java.io. DataInputStream; import java.io. DataOutputStream; import java.net. InetAddress; import java.net. ServerSocket; import java.net. Socket; открытый класс NetworkAppExample {public static void main (String args) выдает исключение {String host = "localhost"; int port = 10430; ServerSocket server = новый ServerSocket (порт, 50, InetAddress.getByName (хост)); System.out.println ("Сервер запущен."); Клиент сокета = новый сокет (хост, порт); System.out.println («Подключение к серверу…»); Соединение сокета = server.accept (); System.out.println ("Соединение установлено."); DataOutputStream clientOut = новый DataOutputStream (client.getOutputStream ()); DataInputStream clientIn = новый DataInputStream (client.getInputStream ()); DataOutputStream serverOut = новый DataOutputStream (connection.getOutputStream ()); DataInputStream serverIn = новый DataInputStream (connection.getInputStream ()); System.out.println («Связь готова.»); byte messageOut = "Привет, мир".getBytes (); }}

  • Потоки объектов

    import java.io. ObjectInputStream; import java.io. ObjectOutputStream; import java.net. InetAddress; import java.net. ServerSocket; import java.net. Socket; открытый класс NetworkAppExample {public static void main (String args) выдает исключение {String host = "localhost"; int port = 10430; ServerSocket server = новый ServerSocket (порт, 50, InetAddress.getByName (хост)); System.out.println ("Сервер запущен."); Клиент сокета = новый сокет (хост, порт); System.out.println («Подключение к серверу…»); Соединение сокета = server.accept (); System.out.println ("Соединение установлено."); ObjectOutputStream clientOut = новый ObjectOutputStream (client.getOutputStream ()); ObjectOutputStream serverOut = новый ObjectOutputStream (connection.getOutputStream ()); ObjectInputStream clientIn = новый ObjectInputStream (client.getInputStream ()); ObjectInputStream serverIn = новый ObjectInputStream (connection.getInputStream ()); System.out.println («Связь готова.»); String messageOut = "Hello World"; }}

Создайте сетевое приложение на Java Step13
Создайте сетевое приложение на Java Step13

Шаг 13. Отправьте сообщение

Запишите данные в выходной поток и очистите поток, чтобы убедиться, что данные были записаны полностью.

  • Потоки данных

    Длина сообщения должна быть отправлена первой, чтобы другая сторона знала, сколько байтов ей нужно прочитать. После того, как длина будет отправлена как примитивный целочисленный тип, можно отправлять байты.

    import java.io. DataInputStream; import java.io. DataOutputStream; import java.net. InetAddress; import java.net. ServerSocket; import java.net. Socket; открытый класс NetworkAppExample {public static void main (String args) выдает исключение {String host = "localhost"; int port = 10430; ServerSocket server = новый ServerSocket (порт, 50, InetAddress.getByName (хост)); System.out.println ("Сервер запущен."); Клиент сокета = новый сокет (хост, порт); System.out.println («Подключение к серверу…»); Соединение сокета = server.accept (); System.out.println ("Соединение установлено."); DataOutputStream clientOut = новый DataOutputStream (client.getOutputStream ()); DataInputStream clientIn = новый DataInputStream (client.getInputStream ()); DataOutputStream serverOut = новый DataOutputStream (connection.getOutputStream ()); DataInputStream serverIn = новый DataInputStream (connection.getInputStream ()); System.out.println («Связь готова.»); byte messageOut = "Привет, мир".getBytes (); clientOut.writeInt (messageOut.length); clientOut.write (messageOut); clientOut.flush (); }}

  • Потоки объектов

    import java.io. ObjectInputStream; import java.io. ObjectOutputStream; import java.net. InetAddress; import java.net. ServerSocket; import java.net. Socket; открытый класс NetworkAppExample {public static void main (String args) выдает исключение {String host = "localhost"; int port = 10430; ServerSocket server = новый ServerSocket (порт, 50, InetAddress.getByName (хост)); System.out.println ("Сервер запущен."); Клиент сокета = новый сокет (хост, порт); System.out.println («Подключение к серверу…»); Соединение сокета = server.accept (); System.out.println («Соединение установлено.»); ObjectOutputStream clientOut = новый ObjectOutputStream (client.getOutputStream ()); ObjectOutputStream serverOut = новый ObjectOutputStream (connection.getOutputStream ()); ObjectInputStream clientIn = новый ObjectInputStream (client.getInputStream ()); ObjectInputStream serverIn = новый ObjectInputStream (connection.getInputStream ()); System.out.println («Связь готова.»); String messageOut = "Привет, мир"; clientOut.writeObject (messageOut); clientOut.flush (); }}

Создайте сетевое приложение на Java Step14
Создайте сетевое приложение на Java Step14

Шаг 14. Зарегистрируйте отправленное сообщение

Для ведения журнала распечатайте на консоли, что сообщение было отправлено.

  • Потоки данных

    import java.io. DataInputStream; import java.io. DataOutputStream; import java.net. InetAddress; import java.net. ServerSocket; import java.net. Socket; открытый класс NetworkAppExample {public static void main (String args) выдает исключение {String host = "localhost"; int port = 10430; ServerSocket server = новый ServerSocket (порт, 50, InetAddress.getByName (хост)); System.out.println ("Сервер запущен."); Клиент сокета = новый сокет (хост, порт); System.out.println («Подключение к серверу…»); Соединение сокета = server.accept (); System.out.println ("Соединение установлено."); DataOutputStream clientOut = новый DataOutputStream (client.getOutputStream ()); DataInputStream clientIn = новый DataInputStream (client.getInputStream ()); DataOutputStream serverOut = новый DataOutputStream (connection.getOutputStream ()); DataInputStream serverIn = новый DataInputStream (connection.getInputStream ()); System.out.println («Связь готова.»); byte messageOut = "Привет, мир".getBytes (); clientOut.writeInt (messageOut.length); clientOut.write (messageOut); clientOut.flush (); System.out.println ("Сообщение отправлено на сервер:" + новая строка (messageOut)); }}

  • Потоки объектов

    import java.io. ObjectInputStream; import java.io. ObjectOutputStream; import java.net. InetAddress; import java.net. ServerSocket; import java.net. Socket; открытый класс NetworkAppExample {public static void main (String args) выдает исключение {String host = "localhost"; int port = 10430; ServerSocket server = новый ServerSocket (порт, 50, InetAddress.getByName (хост)); System.out.println ("Сервер запущен."); Клиент сокета = новый сокет (хост, порт); System.out.println («Подключение к серверу…»); Соединение сокета = server.accept (); System.out.println ("Соединение установлено."); ObjectOutputStream clientOut = новый ObjectOutputStream (client.getOutputStream ()); ObjectOutputStream serverOut = новый ObjectOutputStream (connection.getOutputStream ()); ObjectInputStream clientIn = новый ObjectInputStream (client.getInputStream ()); ObjectInputStream serverIn = новый ObjectInputStream (connection.getInputStream ()); System.out.println («Связь готова.»); String messageOut = "Hello World"; clientOut.writeObject (messageOut); clientOut.flush (); System.out.println ("Сообщение отправлено на сервер:" + messageOut); }}

Создайте сетевое приложение на Java Step15
Создайте сетевое приложение на Java Step15

Шаг 15. Прочтите сообщение

Считайте данные из входного потока и преобразуйте их. Поскольку мы точно знаем тип отправленных данных, мы либо создадим

Нить

из

байт

или бросить

Объект

к

Нить

без проверки, в зависимости от используемого потока.

  • Потоки данных

    Поскольку первой была отправлена длина, а затем байты, чтение должно выполняться в том же порядке. Если длина равна нулю, читать нечего. Объект десериализуется, когда байты преобразуются обратно в экземпляр, в данном случае

    Нить

    import java.io. DataInputStream; import java.io. DataOutputStream; import java.net. InetAddress; import java.net. ServerSocket; import java.net. Socket; открытый класс NetworkAppExample {public static void main (String args) выдает исключение {String host = "localhost"; int port = 10430; ServerSocket server = новый ServerSocket (порт, 50, InetAddress.getByName (хост)); System.out.println ("Сервер запущен."); Клиент сокета = новый сокет (хост, порт); System.out.println («Подключение к серверу…»); Соединение сокета = server.accept (); System.out.println ("Соединение установлено."); DataOutputStream clientOut = новый DataOutputStream (client.getOutputStream ()); DataInputStream clientIn = новый DataInputStream (client.getInputStream ()); DataOutputStream serverOut = новый DataOutputStream (connection.getOutputStream ()); DataInputStream serverIn = новый DataInputStream (connection.getInputStream ()); System.out.println («Связь готова.»); byte messageOut = "Привет, мир".getBytes (); clientOut.writeInt (messageOut.length); clientOut.write (messageOut); clientOut.flush (); System.out.println ("Сообщение отправлено на сервер:" + новая строка (messageOut)); int length = serverIn.readInt (); если (длина> 0) {byte messageIn = новый байт [длина]; serverIn.readFully (messageIn, 0, messageIn.length); }}}

  • Потоки объектов

    import java.io. ObjectInputStream; import java.io. ObjectOutputStream; import java.net. InetAddress; import java.net. ServerSocket; import java.net. Socket; открытый класс NetworkAppExample {public static void main (String args) выдает исключение {String host = "localhost"; int port = 10430; ServerSocket server = новый ServerSocket (порт, 50, InetAddress.getByName (хост)); System.out.println ("Сервер запущен."); Клиент сокета = новый сокет (хост, порт); System.out.println («Подключение к серверу…»); Соединение сокета = server.accept (); System.out.println ("Соединение установлено."); ObjectOutputStream clientOut = новый ObjectOutputStream (client.getOutputStream ()); ObjectOutputStream serverOut = новый ObjectOutputStream (connection.getOutputStream ()); ObjectInputStream clientIn = новый ObjectInputStream (client.getInputStream ()); ObjectInputStream serverIn = новый ObjectInputStream (connection.getInputStream ()); System.out.println («Связь готова.»); String messageOut = "Hello World"; clientOut.writeObject (messageOut); clientOut.flush (); System.out.println ("Сообщение отправлено на сервер:" + messageOut); String messageIn = (String) serverIn.readObject (); }}

Создайте сетевое приложение на Java Step16
Создайте сетевое приложение на Java Step16

Шаг 16. Зарегистрируйте прочитанное сообщение

Для ведения журнала распечатайте на консоли, что сообщение было получено, и распечатайте его содержимое.

  • Потоки данных

    import java.io. DataInputStream; import java.io. DataOutputStream; import java.net. InetAddress; import java.net. ServerSocket; import java.net. Socket; открытый класс NetworkAppExample {public static void main (String args) выдает исключение {String host = "localhost"; int port = 10430; ServerSocket server = новый ServerSocket (порт, 50, InetAddress.getByName (хост)); System.out.println ("Сервер запущен."); Клиент сокета = новый сокет (хост, порт); System.out.println («Подключение к серверу…»); Соединение сокета = server.accept (); System.out.println ("Соединение установлено."); DataOutputStream clientOut = новый DataOutputStream (client.getOutputStream ()); DataInputStream clientIn = новый DataInputStream (client.getInputStream ()); DataOutputStream serverOut = новый DataOutputStream (connection.getOutputStream ()); DataInputStream serverIn = новый DataInputStream (connection.getInputStream ()); System.out.println («Связь готова.»); byte messageOut = "Привет, мир".getBytes (); clientOut.writeInt (messageOut.length); clientOut.write (messageOut); clientOut.flush (); System.out.println ("Сообщение отправлено на сервер:" + новая строка (messageOut)); int length = serverIn.readInt (); если (длина> 0) {byte messageIn = новый байт [длина]; serverIn.readFully (messageIn, 0, messageIn.length); System.out.println ("Сообщение получено от клиента:" + новая строка (messageIn)); }}}

  • Потоки объектов

    import java.io. ObjectInputStream; import java.io. ObjectOutputStream; import java.net. InetAddress; import java.net. ServerSocket; import java.net. Socket; открытый класс NetworkAppExample {public static void main (String args) выдает исключение {String host = "localhost"; int port = 10430; ServerSocket server = новый ServerSocket (порт, 50, InetAddress.getByName (хост)); System.out.println ("Сервер запущен."); Клиент сокета = новый сокет (хост, порт); System.out.println («Подключение к серверу…»); Соединение сокета = server.accept (); System.out.println ("Соединение установлено."); ObjectOutputStream clientOut = новый ObjectOutputStream (client.getOutputStream ()); ObjectOutputStream serverOut = новый ObjectOutputStream (connection.getOutputStream ()); ObjectInputStream clientIn = новый ObjectInputStream (client.getInputStream ()); ObjectInputStream serverIn = новый ObjectInputStream (connection.getInputStream ()); System.out.println («Связь готова.»); String messageOut = "Hello World"; clientOut.writeObject (messageOut); clientOut.flush (); System.out.println ("Сообщение отправлено на сервер:" + messageOut); String messageIn = (String) serverIn.readObject (); System.out.println ("Сообщение получено от клиента:" + messageIn); }}

Создайте сетевое приложение на Java Step17
Создайте сетевое приложение на Java Step17

Шаг 17. Отсоедините соединения

Соединение разрывается, когда одна из сторон закрывает свои потоки. В Java при закрытии выходного потока также закрываются связанный сокет и входной поток. Как только сторона на другом конце обнаруживает, что соединение разорвано, ему также необходимо закрыть свой выходной поток, чтобы предотвратить утечку памяти.

// код пропущен import java.net. InetAddress; import java.net. ServerSocket; import java.net. Socket; открытый класс NetworkAppExample {public static void main (String args) выдает исключение {String host = "localhost"; int port = 10430; ServerSocket server = новый ServerSocket (порт, 50, InetAddress.getByName (хост)); System.out.println ("Сервер запущен."); Клиент сокета = новый сокет (хост, порт); System.out.println («Подключение к серверу…»); Соединение сокета = server.accept (); System.out.println ("Соединение установлено."); // код пропущен System.out.println ("Связь готова."); // код пропущен clientOut.close (); serverOut.close (); }}

Создание сетевого приложения на Java Step18 V2
Создание сетевого приложения на Java Step18 V2

Шаг 18. Отключение журнала

В целях ведения журнала печать для подключения консоли была отключена.

// код пропущен import java.net. InetAddress; import java.net. ServerSocket; import java.net. Socket; открытый класс NetworkAppExample {public static void main (String args) выдает исключение {String host = "localhost"; int port = 10430; ServerSocket server = новый ServerSocket (порт, 50, InetAddress.getByName (хост)); System.out.println ("Сервер запущен."); Клиент сокета = новый сокет (хост, порт); System.out.println («Подключение к серверу…»); Соединение сокета = server.accept (); System.out.println ("Соединение установлено."); // код пропущен System.out.println ("Связь готова."); // код пропущен clientOut.close (); serverOut.close (); System.out.println ("Соединения закрыты."); }}

Создайте сетевое приложение на Java Step19
Создайте сетевое приложение на Java Step19

Шаг 19. Завершите работу сервера

Соединения отключены, но сервер все еще работает. В качестве

ServerSocket

не связан ни с одним потоком, его необходимо явно закрыть, вызвав

близко()

метод.

// код пропущен import java.net. InetAddress; import java.net. ServerSocket; import java.net. Socket; открытый класс NetworkAppExample {public static void main (String args) выдает исключение {String host = "localhost"; int port = 10430; ServerSocket server = новый ServerSocket (порт, 50, InetAddress.getByName (хост)); System.out.println ("Сервер запущен."); Клиент сокета = новый сокет (хост, порт); System.out.println («Подключение к серверу…»); Соединение сокета = server.accept (); System.out.println ("Соединение установлено."); // код пропущен System.out.println ("Связь готова."); // код пропущен clientOut.close (); serverOut.close (); System.out.println ("Соединения закрыты."); server.close (); }}

Создайте сетевое приложение на Java Step20
Создайте сетевое приложение на Java Step20

Шаг 20. Завершение работы сервера журнала

В целях ведения журнала печать на консольный сервер была прекращена.

// код пропущен import java.net. InetAddress; import java.net. ServerSocket; import java.net. Socket; открытый класс NetworkAppExample {public static void main (String args) выдает исключение {String host = "localhost"; int port = 10430; ServerSocket server = новый ServerSocket (порт, 50, InetAddress.getByName (хост)); System.out.println ("Сервер запущен."); Клиент сокета = новый сокет (хост, порт); System.out.println («Подключение к серверу…»); Соединение сокета = server.accept (); System.out.println ("Соединение установлено."); // код пропущен System.out.println ("Связь готова."); // код пропущен clientOut.close (); serverOut.close (); System.out.println ("Соединения закрыты."); server.close (); System.out.println ("Сервер завершен."); }}

Создайте сетевое приложение на Java Step21
Создайте сетевое приложение на Java Step21

Шаг 21. Скомпилируйте и запустите

Ведение журнала позволило нам узнать, было ли приложение успешным или нет. Ожидаемый результат:

Сервер запущен. Подключение к серверу… Соединение установлено. Связь готова. Сообщение, отправленное на сервер: Hello World Сообщение, полученное от клиента: Hello World Соединения закрыты. Сервер отключен.

Если ваш результат отличается от приведенного выше, что маловероятно, есть несколько решений:

  • Если вывод останавливается на строке

    Соединение установлено.

    и потоки объектов используются, очистить каждый

    ObjectOutputStream

  • сразу после инициализации, потому что заголовки по какой-то причине не отправлялись.
  • Если вывод распечатывается

    java.net. BindException: адрес уже используется

  • выберите другой номер порта, потому что указанный уже используется.

подсказки

  • Подключение к серверу в другой сети осуществляется путем подключения к внешнему IP-адресу устройства, на котором запущен сервер с переадресованным портом.
  • Подключение к серверу в той же сети осуществляется либо путем подключения к частному IP-адресу устройства, на котором запущен сервер, либо путем перенаправления порта и подключения к внешнему IP-адресу устройства.
  • Есть программное обеспечение, такое как Hamachi, которое позволяет подключаться к серверу в другой сети без перенаправления порта, но требует установки программного обеспечения на обоих устройствах.

Примеры

Сетевые приложения, использующие блокировку ввода / вывода, должны использовать потоки. В следующих примерах показана минималистичная реализация сервера и клиента с потоками. Сетевой код по сути такой же, как в статье, за исключением того, что некоторые фрагменты были синхронизированы, перемещены в потоки и обработаны исключения.

Server.java

import java.io. IOException; import java.net. InetAddress; import java.net. ServerSocket; import java.net. SocketException; import java.net. UnknownHostException; import java.util. ArrayList; import java.util. Collections; import java.util. List; / ** * Класс {@code Server} представляет конечную точку сервера в сети. {@code Server}, будучи привязанным к определенному IP-адресу * и порту, устанавливает соединения с клиентами и может связываться с ними или отключать их. *

* Этот класс является потокобезопасным. * * @version 1.0 * @see Client * @see Connection * / открытый класс Server реализует Runnable {частный сервер ServerSocket; частный список соединения; частный поток потока; закрытый конечный объект ConnectionLock = новый объект (); / ** * Создает {@code Server}, который взаимодействует с клиентами на указанном имени хоста и порту с указанной * запрошенной максимальной длиной очереди входящих клиентов. * * @param host Используемый адрес хоста. * @param port Номер используемого порта. * @param backlog Запрошенная максимальная длина очереди входящих клиентов. * @throws NetworkException Если ошибка возникает при запуске сервера. * / public Server (String host, int port, int backlog) выбрасывает NetworkException {try {server = new ServerSocket (port, backlog, InetAddress.getByName (host)); } catch (UnknownHostException e) {throw new NetworkException ("Имя хоста не может быть разрешено:" + host, e); } catch (IllegalArgumentException e) {throw new NetworkException ("Номер порта должен быть от 0 до 65535 (включительно):" + порт); } catch (IOException e) {throw new NetworkException ("Сервер не может быть запущен.", e); } соединения = Collections.synchronizedList (новый ArrayList ()); thread = новый поток (это); thread.start (); } / ** * Создает {@code Server}, который взаимодействует с клиентами на указанном имени хоста и порту. * * @param host Адрес хоста для привязки. * @param port Номер порта для привязки. * @throws NetworkException Если при запуске сервера возникают ошибки. * / public Server (String host, int port) выбрасывает NetworkException {this (host, port, 50); } / ** * Прослушивает, принимает и регистрирует входящие соединения от клиентов. * / @Override public void run () {while (! Server.isClosed ()) {try {connections.add (new Connection (server.accept ())); } catch (SocketException e) {если (! e.getMessage (). equals ("Сокет закрыт")) {e.printStackTrace (); }} catch (NetworkException | IOException e) {e.printStackTrace (); }}} / ** * Отправляет данные всем зарегистрированным клиентам. * * @param data Данные для отправки. * @throws IllegalStateException При попытке записи данных, когда сервер отключен. * @throws IllegalArgumentException Если данные для отправки равны нулю. * / public void broadcast (Object data) {if (server.isClosed ()) {throw new IllegalStateException («Данные не отправлены, сервер отключен.»); } if (data == null) {выбросить новое исключение IllegalArgumentException ("нулевые данные"); } синхронизировано (connectionsLock) {для (Соединение соединение: соединения) {попробуйте {соединение.send (данные); System.out.println ("Данные успешно отправлены клиенту."); } catch (NetworkException e) {e.printStackTrace (); }}}} / ** * Отправляет сообщение об отключении и отключает указанного клиента. * * @param connection Клиент для отключения. * @throws NetworkException Если при закрытии соединения возникает ошибка. * / public void disconnect (Connection connection) выбрасывает NetworkException {if (connections.remove (connection)) {connection.close (); }} / ** * Отправляет сообщение об отключении всем клиентам, отключает их и завершает работу сервера. * / public void close () выбрасывает NetworkException {synchronized (connectionsLock) {для (Connection connection: connections) {try {connection.close (); } catch (NetworkException e) {e.printStackTrace (); }}} connections.clear (); попробуйте {server.close (); } catch (IOException e) {throw new NetworkException ("Ошибка при закрытии сервера."); } наконец {thread.interrupt (); }} / ** * Возвращает, находится ли сервер в сети. * * @return Истина, если сервер в сети. В противном случае - ложь. * / public boolean isOnline () {return! server.isClosed (); } / ** * Возвращает массив зарегистрированных клиентов. * / public Connection getConnections () {synchronized (connectionsLock) {return connections.toArray (new Connection [connections.size ()]); }}}

Client.java

import java.io. IOException; import java.net. Socket; import java.net. UnknownHostException; / ** * Класс {@code Client} представляет конечную точку клиента в сети. {@code Client} после подключения к определенному * серверу гарантированно сможет связываться только с этим сервером. Получат или нет данные другие клиенты *, зависит от реализации сервера. *

* Этот класс является потокобезопасным. * * @version 1.0 * @see Server * @see Connection * / клиент открытого класса {частное соединение Connection; / ** * Создает {@code Client}, подключенного к серверу на указанном хосте и порту. * * @param host Адрес хоста для привязки. * @param port Номер порта для привязки. * @throws NetworkException Если ошибка возникает при запуске сервера. * / public Client (String host, int port) выбрасывает NetworkException {try {connection = new Connection (new Socket (host, port)); } catch (UnknownHostException e) {throw new NetworkException ("Имя хоста не может быть разрешено:" + host, e); } catch (IllegalArgumentException e) {throw new NetworkException ("Номер порта должен быть от 0 до 65535 (включительно):" + порт); } catch (IOException e) {throw new NetworkException ("Сервер не может быть запущен.", e); }} / ** * Отправляет данные другой стороне. * * @param data Данные для отправки. * @throws NetworkException Если запись в выходной поток не удалась. * @throws IllegalStateException При попытке записи данных при закрытии соединения. * @throws IllegalArgumentException Если данные для отправки равны нулю. * @throws UnsupportedOperationException При попытке отправки неподдерживаемого типа данных. * / public void send (данные объекта) выбрасывает исключение NetworkException {connection.send (data); } / ** * Отправляет сообщение об отключении и закрывает соединение с сервером. * / public void close () выбрасывает NetworkException {connection.close (); } / ** * Возвращает, подключен ли клиент к серверу. * * @return Истинно, если клиент подключен. В противном случае - ложь. * / public boolean isOnline () {return connection.isConnected (); } / ** * Возвращает экземпляр {@link Connection} клиента. * / public Connection getConnection () {return connection; }}

Connection.java

import java.io. DataInputStream; import java.io. DataOutputStream; import java.io. IOException; import java.net. Socket; import java.net. SocketException; / ** * Класс {@code Connection} представляет либо соединение от сервера к клиенту, либо конечную точку клиента в сети * {@code Connection} после подключения может обмениваться данными с другой стороной или сторонами, в зависимости от на сервере * реализация. *

* Этот класс является потокобезопасным. * * @version 1.0 * @see Server * @see Client * / открытый класс Connection реализует Runnable {private Socket socket; частный выход DataOutputStream; частный DataInputStream in; частный поток потока; закрытый конечный объект writeLock = новый объект (); закрытый конечный объект readLock = новый объект (); / ** * Создает {@code Connection} с использованием потоков указанного {@link Socket}. * * @param socket Сокет, из которого выбираются потоки.* / public Connection (Socket socket) выбрасывает NetworkException {if (socket == null) {throw new IllegalArgumentException ("null socket"); } this.socket = сокет; попробуйте {out = new DataOutputStream (socket.getOutputStream ()); } catch (IOException e) {throw new NetworkException ("Не удалось получить доступ к потоку вывода.", e); } попробуйте {in = new DataInputStream (socket.getInputStream ()); } catch (IOException e) {throw new NetworkException ("Не удалось получить доступ к входному потоку.", e); } thread = новый поток (это); thread.start (); } / ** * Читает сообщения, пока активно соединение с другой стороной. * / @Override public void run () {while (! Socket.isClosed ()) {try {int identifier; byte байты; синхронизированный (readLock) {идентификатор = in.readInt (); int length = in.readInt (); если (длина> 0) {байты = новый байт [длина]; in.readFully (байты, 0, длина байтов); } else {продолжить; }} переключатель (идентификатор) {case Identifier. INTERNAL: String command = new String (bytes); if (command.equals ("отключить")) {if (! socket.isClosed ()) {System.out.println ("Получен пакет отключения."); попробуйте {close (); } catch (NetworkException e) {возврат; } } } перерыв; case Identifier. TEXT: System.out.println («Сообщение получено:» + новая строка (байты)); перерыв; по умолчанию: System.out.println («Получены нераспознанные данные.»); }} catch (SocketException e) {if (! e.getMessage (). equals ("Socket closed")) {e.printStackTrace (); }} catch (IOException e) {e.printStackTrace (); }}} / ** * Отправляет данные другой стороне. * * @param data Данные для отправки. * @throws NetworkException Если запись в выходной поток не удалась. * @throws IllegalStateException При попытке записи данных при закрытии соединения. * @throws IllegalArgumentException Если данные для отправки равны нулю. * @throws UnsupportedOperationException При попытке отправки неподдерживаемого типа данных. * / public void send (данные объекта) выбрасывает NetworkException {if (socket.isClosed ()) {throw new IllegalStateException ("Данные не отправлены, соединение закрыто."); } if (data == null) {выбросить новое исключение IllegalArgumentException ("нулевые данные"); } int идентификатор; byte байты; если (экземпляр данных String) {идентификатор = Идентификатор. ТЕКСТ; bytes = ((Строка) данные).getBytes (); } else {выбросить новое исключение UnsupportedOperationException ("Неподдерживаемый тип данных:" + data.getClass ()); } попробуйте {синхронизировано (writeLock) {out.writeInt (идентификатор); out.writeInt (длина байтов); out.write (байты); out.flush (); }} catch (IOException e) {throw new NetworkException ("Данные не могут быть отправлены.", e); }} / ** * Отправляет сообщение об отключении и закрывает соединение с другой стороной. * / public void close () выбрасывает NetworkException {if (socket.isClosed ()) {throw new IllegalStateException ("Соединение уже закрыто."); } попробуйте {byte message = "отключить".getBytes (); синхронизированный (writeLock) {out.writeInt (Identifier. INTERNAL); out.writeInt (длина сообщения); out.write (сообщение); out.flush (); }} catch (IOException e) {System.out.println ("Сообщение об отключении не может быть отправлено."); } попробуйте {синхронизировано (writeLock) {out.close (); }} catch (IOException e) {throw new NetworkException ("Ошибка при закрытии соединения.", e); } наконец {thread.interrupt (); }} / ** * Возвращает, активно ли соединение с другой стороной. * * @return Истинно, если соединение активно. В противном случае - ложь. * / public boolean isConnected () {return! socket.isClosed (); }}

Identifier.java

/ ** * Класс {@code Identifier} содержит константы, используемые {@link Connection} для сериализации и десериализации данных *, отправляемых по сети. * * @version 1.0 * @see Connection * / public final class Identifier {/ ** * Идентификатор для внутренних сообщений. * / public static final int INTERNAL = 1; / ** * Идентификатор текстовых сообщений. * / public static final int TEXT = 2; }

NetworkException.java

/ ** * Класс {@code NetworkException} указывает на ошибку, связанную с сетью. * / public class NetworkException extends Exception {/ ** * Создает {@code NetworkException} с {@code null} в качестве сообщения. * / public NetworkException () {} / ** * Создает {@code NetworkException} с указанным сообщением. * * @param message Сообщение, описывающее ошибку. * / public NetworkException (строковое сообщение) {super (сообщение); } / ** * Создает {@code NetworkException} с указанным сообщением и причиной. * * @param message Сообщение, описывающее ошибку. * @param cause Причина ошибки. * / public NetworkException (String message, Throwable cause) {super (message, cause); } / ** * Создает {@code NetworkException} с указанной причиной. * * @param причина Причина ошибки. * / public NetworkException (Выбрасываемая причина) {super (причина); }}

UsageExample.java

/ ** * Класс {@code UsageExample} показывает использование {@link Server} и {@link Client}. В этом примере используется * {@link Thread # sleep (long)}, чтобы гарантировать выполнение каждого сегмента, поскольку при быстром запуске и закрытии некоторые * сегменты не выполняются. * * @version 1.0 * @see Server * @see Client * / public class UsageExample {public static void main (String args) выдает исключение {String host = "localhost"; int port = 10430; Сервер server = новый Сервер (хост, порт); Клиент-клиент = новый клиент (хост, порт); Thread.sleep (100л); client.send ("Привет."); server.broadcast («Эй, парень!»); Thread.sleep (100л); server.disconnect (server.getConnections () [0]); // или client.close () для отключения от клиента server.close (); }}

Рекомендуемые: