#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. Спасибо. Я пытался (см. Мои правки), но это не работает: я больше не получаю исключение, но я также не получаю сообщения, отправленные сервером.