Страницы

Поиск по вопросам

четверг, 11 июля 2019 г.

неблокирующий udp-сокет в java

Есть сервер, на котором должен работать демон (фоновый процесс, не важно как назвать) постоянно обрабатывающий массив информации. Периодически он должен проверять не пришли ли какие-то сообщения от сетевых клиентов и, если пришли, записывать их в базу. Из-за определённых ограничений клиенты отправляют серверу сообщения исключительно по udp протоколу. Если я правильно понял прочитанную литературу по работе с udp-сокетами, то выглядеть это будет примерно так:
-где-то вначале инициализируем сокет на определённом порту
try { socket = new DatagramSocket(port); } catch (SocketException e) { // Сообщение об ошибке, возможно остановка всего демона, если ничего не вышло }
-далее выполняем основную работу демона и в определённые моменты пытаемся получить информацию из сокета:
byte[] bytes = new byte[1024]; DatagramPacket p = new DatagramPacket(bytes, bytes.length); try { socket.receive(p); } catch(IOException e) { }
Насколько я понимаю, если ни один клиент не прислал пакета данных, то на данном этапе всё остановится и процесс будет ждать прихода данных на сокет. Правильно? А мне необходимо, чтоб работа продолжалась независимо от того, получены данные или нет. Если получены - хорошо - записали их в базу, если нет, ну и ладно - ещё масса работы. В C++ существует возможность перевода сокета в неблокирующий режим, выглядит это приблизительно так:
int nonBlocking = 1; if ( fcntl( handle, F_SETFL, O_NONBLOCK, nonBlocking ) == -1 ) { printf( "failed to set non-blocking socket
" ); }
для UNIX и MAC и
DWORD nonBlocking = 1; if ( ioctlsocket( handle, FIONBIO, &nonBlocking ) != 0 ) { printf( "failed to set non-blocking socket
" ); }
для WINDOWS где handle - дескриптор сокета. При таком режиме, при чтении из сокета, в случае, когда данные в нём отсутствуют,
int received_bytes = recvfrom( handle, (char*)packet_data, maximum_packet_size, 0, (sockaddr*)&from, &fromLength );
программа не остановится, а received_bytes просто будет равно нулю. Существует ли в Java возможность переводить udp-сокет в неблокирующий режим? Или необходимо опрос сокета вести в отдельном потоке и при получении данных реализовывать какую-то событийность? Неблокирующие сокеты, в моём случае, были бы хороши тем, что опрос сокета должен проводиться в определённые моменты обработки основных данных и если получена какая-то информация, то она должна быть сохранена с привязкой к определённым ключам из основных данных, в остальное время пришедшие udp-пакеты неважны, их можно просто сбрасывать. Бегло пробежавшись по результатам поисковых запросов не нашёл необходимого мне функционала в Java.

Почему поток для меня неудобен, попробую объяснить: всё это дело связано со сложной системой охранной сигнализации и видеонаблюдения. Грубо говоря: одни железки (железо1) постоянно пишут какие-то данные в базу. Один из процессов на сервере (процесс1) эту базу постоянно контролирует и при обнаружении в ней определённых новых данных рассылает другим железкам (железо2) сообщения. Те, в свою очередь, получив сообщения проводят определённые действия и проверки (это занимает какое-то небольшое время) и при возникновении у них каких-то событий отправляют данные на сервер по протоколу udp. Возникла задача получать эти сообщения (не критично, если некоторые будут теряться), сравнивать с данными из базы и при некоторых совпадениях - логировать. Существующее программное обеспечение не изменить - нет исходников. Так вот проблема в том, что железо2, присылая сообщения, не ставит там никаких временных меток. А ещё оно может самостоятельно присылать сообщения, не инициированные запросами от процесса1. И мне было бы удобно в моём процессе мониторить базу (одновременно с другим процессом, это уже реализовано и сложностей с этим не возникает) и пытаться считать данные из сокета только в определённые моменты, когда там (в базе) появляются конкретные данные (эти события происходят довольно редко, раз в два-три часа), а в остальное время просто периодически сбрасывать данные сокета (если железо2 туда что-то прислало), как ненужные. Иначе я могу получить кучу данных, присланных за последнее время, которые к нужным мне событиям отношения не имеют, но выяснить это можно лишь дифференцировав это всё по времени, а временных меток (повторюсь) в сообщениях железа2 нет Если реализовывать это в отдельном потоке, то для меня возникают определённые сложности с созданием событий и их вызовом. А неблокирующий сокет в этом случае - идеальное решение. Тем более, что такая функциональность на C++ точно есть, она работает и работает прекрасно. Вот и возник вопрос: возможно подобный функционал есть и у Java? Заодно, раз уж приходится всё делать именно на этом языке программирования, буду развиваться и учить для себя что-то новое.


Ответ

В Java все non-blocking IO содержится в пакете java.nio.channels. Неблокирующее UDP реализовано классом DatagramChannel
Пользоваться можно как-то так:
DatagramChannel chan = DatagramChannel.open(); chan.configureBlocking( false ); chan.bind( new InetSocketAddress( 7777 ) );
ByteBuffer buffer = ByteBuffer.allocate( 4*1024 );
while (true) { buffer.clear(); System.out.println("trying non-blocking receive..."); SocketAddress from = chan.receive(buffer); System.out.println("non-blocking receive done.");
if (from != null) { buffer.flip(); System.out.printf("<<<--- got [%x] byte from %s%n", buffer.get(), from); }
System.out.println( "sleeping..." ); TimeUnit.SECONDS.sleep( 5 ); }

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

Отправить комментарий