Java Language
NIO - Сеть
Поиск…
замечания
SelectionKey
определяет различные выбираемые операции и информацию между его Селектором и Каналом . В частности, вложение может использоваться для хранения связанной с подключением информации.
Обработка OP_READ
довольно прямолинейна. Однако следует соблюдать осторожность при работе с OP_WRITE
: большую часть времени данные могут быть записаны в сокеты, чтобы событие продолжало стрелять. Обязательно зарегистрируйте OP_WRITE
только до того, как вы захотите записать данные (см. OP_WRITE
ответ ).
Кроме того , OP_CONNECT
должен быть отменен после того , как канал был подключен (потому что, ну, это связано. См это и что ответы на SO). Следовательно, удаление OP_CONNECT
после finishConnect()
преуспело.
Использование Selector для ожидания событий (пример с OP_CONNECT)
NIO появился на Java 1.4 и представил концепцию «Каналы», которые должны быть быстрее, чем обычные входы / выходы. По сетевому интерфейсу SelectableChannel
является самым интересным, поскольку он позволяет контролировать различные состояния канала. Он работает так же, как и системный вызов C select()
: мы пробуждаемся, когда происходят определенные типы событий:
- полученное соединение (
OP_ACCEPT
) - реализовано соединение (
OP_CONNECT
) - данные доступны в считываемом FIFO (
OP_READ
) - данные могут быть
OP_WRITE
для записи FIFO (OP_WRITE
)
Он позволяет разделить между обнаружением ввода-вывода сокетов (что-то можно прочитать / записать / ...) и выполнить ввод-вывод (чтение / запись / ...). В частности, все обнаружение ввода-вывода может выполняться в одном потоке для нескольких сокетов (клиентов), в то время как операции ввода-вывода могут обрабатываться в пуле потоков или в другом месте. Это позволяет легко масштабировать приложение до количества подключенных клиентов.
В следующем примере показаны основы:
- Создать
Selector
- Создание
SocketChannel
- Зарегистрируйте
SocketChannel
дляSelector
- Цикл с
Selector
для обнаружения событий
Selector sel = Selector.open(); // Create the Selector
SocketChannel sc = SocketChannel.open(); // Create a SocketChannel
sc.configureBlocking(false); // ... non blocking
sc.setOption(StandardSocketOptions.SO_KEEPALIVE, true); // ... set some options
// Register the Channel to the Selector for wake-up on CONNECT event and use some description as an attachement
sc.register(sel, SelectionKey.OP_CONNECT, "Connection to google.com"); // Returns a SelectionKey: the association between the SocketChannel and the Selector
System.out.println("Initiating connection");
if (sc.connect(new InetSocketAddress("www.google.com", 80)))
System.out.println("Connected"); // Connected right-away: nothing else to do
else {
boolean exit = false;
while (!exit) {
if (sel.select(100) == 0) // Did something happen on some registered Channels during the last 100ms?
continue; // No, wait some more
// Something happened...
Set<SelectionKey> keys = sel.selectedKeys(); // List of SelectionKeys on which some registered operation was triggered
for (SelectionKey k : keys) {
System.out.println("Checking "+k.attachment());
if (k.isConnectable()) { // CONNECT event
System.out.print("Connected through select() on "+k.channel()+" -> ");
if (sc.finishConnect()) { // Finish connection process
System.out.println("done!");
k.interestOps(k.interestOps() & ~SelectionKey.OP_CONNECT); // We are already connected: remove interest in CONNECT event
exit = true;
} else
System.out.println("unfinished...");
}
// TODO: else if (k.isReadable()) { ...
}
keys.clear(); // Have to clear the selected keys set once processed!
}
}
System.out.print("Disconnecting ... ");
sc.shutdownOutput(); // Initiate graceful disconnection
// TODO: emtpy receive buffer
sc.close();
System.out.println("done");
Дала бы следующий результат:
Initiating connection
Checking Connection to google.com
Connected through 'select()' on java.nio.channels.SocketChannel[connection-pending remote=www.google.com/216.58.208.228:80] -> done!
Disconnecting ... done