Java с несколькими UDP-клиентами, прослушивающими один и тот же порт

#java #sockets #udpclient

#java #сокеты #udpclient

Вопрос:

Допустим, я запускаю простой UDP-сервер: nc -u localhost 10000

И простой UDP-клиент: nc -ul 10000

Тогда возможно ли в Java получать сообщения, отправленные сервером, без получения исключения «Адрес уже используется», потому что клиент уже есть?

РЕДАКТИРОВАТЬ: вот код, который я использую:

 DatagramSocket socket = new DatagramSocket(port);

new Thread(() -> {

    try {

        while(true) {

            byte[] receiveData = new byte[256];
            DatagramPacket receivePacket = new DatagramPacket(receiveData, receiveData.length);
            socket.receive(receivePacket);

            String message = new String( receivePacket.getData(), 0, receivePacket.getLength()).trim();
        }
    }
    catch (SocketException ignore) {}
    catch (IOException e) { e.printStackTrace(); }

}).start();
  

Это приводит к исключению java.net.BindException: адрес уже используется (ошибка привязки).

Используя это:

 DatagramSocket socket = new DatagramSocket(null);
socket.setOption(SO_REUSEPORT, true);
socket.setOption(SO_REUSEADDR, true);

new Thread(() -> {

    try {

        while(true) {

            byte[] receiveData = new byte[256];
            DatagramPacket receivePacket = new DatagramPacket(receiveData, receiveData.length);
            socket.receive(receivePacket);

            String message = new String( receivePacket.getData(), 0, receivePacket.getLength()).trim();
        }
    }
    catch (SocketException ignore) {}
    catch (IOException e) { e.printStackTrace(); }

}).start();
  

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

РЕДАКТИРОВАТЬ 2: в реальной ситуации сервер передает сообщения.

Комментарии:

1. Разве клиент не подключается к серверу через этот данный порт? Этот порт прослушивает сервер . Клиент автоматически назначит другой порт (> 4096) для себя, затем подключится к серверу, сообщая ему, куда отправлять ответы (поскольку пакеты всегда содержат IP-адрес отправителя и получателя и номер порта как часть заголовка пакета).

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

Ответ №1:

Это должно быть возможно с помощью StandardSocketOptions.SO_REUSEPORT :

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

Ядро Linux поддерживает это с версии 3.9.

В Windows вам, возможно, потребуется использовать SO_REUSEADDR , но я не совсем уверен.

Использование SO_REUSEADDR
Опция сокета SO_REUSEADDR позволяет сокету принудительно привязываться к порту, используемому другим сокетом.

Комментарии:

1. Спасибо. Я пытался (см. Мои правки), но это не работает: я больше не получаю исключение, но я также не получаю сообщения, отправленные сервером.