Есть сервер, на котором должен работать демон (фоновый процесс, не важно как назвать) постоянно обрабатывающий массив информации. Периодически он должен проверять не пришли ли какие-то сообщения от сетевых клиентов и, если пришли, записывать их в базу. Из-за определённых ограничений клиенты отправляют серверу сообщения исключительно по 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 );
}
Комментариев нет:
Отправить комментарий