#java #udp #datagram #socketchannel #so-reuseport
Вопрос:
Я должен получать данные от разных клиентов на одном и том же порту сервера. Для этого я хочу создать отдельные каналы для каждого клиента и получать данные по каждому из них.
Я изучаю все доступные варианты для этого дизайна.
Вариант 1 : Прослушивайте один сокет и обрабатывайте данные, поступающие с разных устройств.
Вариант 2.Создайте несколько каналов на одном адресе src (на сервере) с разными удаленными адресами (клиентов) и используйте селектор NIO для обработки данных по этим каналам.
Вариант 1 кажется немного рискованным, так как удаленных устройств огромное количество. И я, похоже, не могу реализовать вариант 2. Я получаю исключение привязки, даже если я использую API setReuseAddress() перед привязкой канала.
Кто-нибудь может мне здесь помочь? Или если есть какой — то лучший способ спроектировать это. Я изучил другие вопросы о stackoverflow, но до сих пор не могу понять, возможно ли это или нет.
Комментарии:
1. Этот вопрос следует закрыть, потому что (1) нет кода, который показывал бы, что ОП пробовал, и объяснял, что именно не работает, и (2) ОП запрашивает альтернативы, что в лучшем случае приведет к самоуверенным ответам. ТАК что это не дискуссионный форум, а платформа для вопросов и ответов. Поэтому этот вопрос не относится к тому, как он написан в настоящее время. Пожалуйста, либо улучшите, либо удалите его полностью.
Ответ №1:
Один UDP-сокет может обслуживать множество клиентов.
Поскольку UDP является протоколом без состояния, вы можете считывать данные со всех этих клиентов, не создавая поток (или канал) для каждого клиента.
int yourPort = // ...
try (DatagramSocket socket = new DatagramSocket(new InetSocketAddress("0.0.0.0", yourPort))) {
byte[] buf = new byte[65535];
DatagramPacket packet = new DatagramPacket(buf, 0, buf.length);
while (socket.isBound() amp;amp; !socket.isClosed()) {
// The packets received here are from all sources, not just a single source
socket.receive(packet);
// If we simply send that same packet, without modifying anything, it
// will echo the same content to whoever sent that packet
socket.send(packet);
}
} catch (IOException e) {
// probably a good idea to close/re-bind here..
}
Приведенный выше фрагмент кода теоретически будет обрабатывать любое количество клиентов, для этого потребуется только один поток. В UDP нет такой концепции сеансовых каналов.
Вы можете (и, вероятно, должны) скопировать полученные данные и обработать их вне этого цикла, чтобы максимально увеличить используемую пропускную способность сети. Это то, что вам придется делать независимо от того, какую стратегию вы выберете.
Нет никаких причин, по которым вышеуказанная реализация была бы значительно менее эффективной, чем другие способы.
- Создание нескольких сокетов не увеличит вашу пропускную способность.
- Идея
setReuseAddress
заключается в том, чтобы разрешить множество регистраций на одной и той же конечной точке многоадресной рассылки. Не для того, чтобы увеличить пропускную способность. - Вы можете увеличить буферы приема и отправки, если считаете, что они могут быть переполнены трафиком, используя
DatagramSocket#setReceiveBufferSize
иDatagramSocket#setSendBufferSize
.