Рубрики
Без рубрики

Руководство По UDP На Java

Краткое и практическое руководство по UDP на Java

Автор оригинала: baeldung.

1. Обзор

В этой статье мы рассмотрим сетевое взаимодействие с Java по протоколу пользовательских дейтаграмм ( UDP ).

UDP-это протокол связи, который передает независимые пакеты по сети без гарантии прибытия и без гарантии заказа доставки .

Большая часть связи через Интернет осуществляется по протоколу управления передачей (TCP), однако UDP имеет свое место, которое мы рассмотрим в следующем разделе.

2. Зачем использовать UDP?

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

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

3. Создание приложений UDP

Создание приложений UDP очень похоже на создание системы TCP; единственное отличие заключается в том, что мы не устанавливаем соединение точка-точка между клиентом и сервером.

Настройка тоже очень проста. Java поставляется со встроенной сетевой поддержкой UDP, которая является частью java.net пакет. Поэтому для выполнения сетевых операций по UDP нам нужно только импортировать классы из java.net пакет: java.net.DatagramSocket и java.net.DatagramPacket .

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

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

4. Сервер

В связи UDP одно сообщение инкапсулируется в пакет DatagramPacket , который отправляется через пакет DatagramSocket .

Давайте начнем с настройки простого сервера:

public class EchoServer extends Thread {

    private DatagramSocket socket;
    private boolean running;
    private byte[] buf = new byte[256];

    public EchoServer() {
        socket = new DatagramSocket(4445);
    }

    public void run() {
        running = true;

        while (running) {
            DatagramPacket packet 
              = new DatagramPacket(buf, buf.length);
            socket.receive(packet);
            
            InetAddress address = packet.getAddress();
            int port = packet.getPort();
            packet = new DatagramPacket(buf, buf.length, address, port);
            String received 
              = new String(packet.getData(), 0, packet.getLength());
            
            if (received.equals("end")) {
                running = false;
                continue;
            }
            socket.send(packet);
        }
        socket.close();
    }
}

Мы создаем глобальный DatagramSocket , который мы будем использовать для отправки пакетов, массив байтов для упаковки наших сообщений и переменную состояния с именем running .

Для простоты сервер расширяет Поток , поэтому мы можем реализовать все внутри метода run .

Внутри run мы создаем цикл while , который просто выполняется до тех пор, пока running не будет изменен на false из-за какой-либо ошибки или сообщения о завершении от клиента.

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

Затем мы вызываем метод receive в сокете. Этот метод блокируется до тех пор, пока не поступит сообщение, и он сохраняет сообщение в массиве байтов переданного ему пакета DatagramPacket .

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

Затем мы создаем DatagramPacket для отправки сообщения клиенту. Обратите внимание на разницу в подписи с получающим пакетом. Для этого также требуется адрес и порт клиента, которому мы отправляем сообщение.

5. Клиент

Теперь давайте развернем простой клиент для этого нового сервера:

public class EchoClient {
    private DatagramSocket socket;
    private InetAddress address;

    private byte[] buf;

    public EchoClient() {
        socket = new DatagramSocket();
        address = InetAddress.getByName("localhost");
    }

    public String sendEcho(String msg) {
        buf = msg.getBytes();
        DatagramPacket packet 
          = new DatagramPacket(buf, buf.length, address, 4445);
        socket.send(packet);
        packet = new DatagramPacket(buf, buf.length);
        socket.receive(packet);
        String received = new String(
          packet.getData(), 0, packet.getLength());
        return received;
    }

    public void close() {
        socket.close();
    }
}

Код не сильно отличается от кода сервера. У нас есть наш глобальный DatagramSocket и адрес сервера. Мы создаем их экземпляры внутри конструктора.

У нас есть отдельный метод, который отправляет сообщения на сервер и возвращает ответ.

Сначала мы преобразуем строковое сообщение в массив байтов, а затем создаем DatagramPacket для отправки сообщений.

Далее – отправляем сообщение. Мы немедленно преобразуем пакет DatagramPacket в принимающий.

Когда приходит эхо, мы преобразуем байты в строку и возвращаем строку.

6. Тест

В классе UDPTest.java , мы просто создаем один тест, чтобы проверить эхо-способность наших двух приложений:

public class UDPTest {
    EchoClient client;

    @Before
    public void setup(){
        new EchoServer().start();
        client = new EchoClient();
    }

    @Test
    public void whenCanSendAndReceivePacket_thenCorrect() {
        String echo = client.sendEcho("hello server");
        assertEquals("hello server", echo);
        echo = client.sendEcho("server is working");
        assertFalse(echo.equals("hello server"));
    }

    @After
    public void tearDown() {
        client.sendEcho("end");
        client.close();
    }
}

В setup мы запускаем сервер , а также создаем клиент. Находясь в методе tearDown , мы отправляем сообщение о завершении на сервер, чтобы он мог закрыться, и в то же время мы закрываем клиента.

7. Заключение

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

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