Поиск…


замечания

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 )

Он позволяет разделить между обнаружением ввода-вывода сокетов (что-то можно прочитать / записать / ...) и выполнить ввод-вывод (чтение / запись / ...). В частности, все обнаружение ввода-вывода может выполняться в одном потоке для нескольких сокетов (клиентов), в то время как операции ввода-вывода могут обрабатываться в пуле потоков или в другом месте. Это позволяет легко масштабировать приложение до количества подключенных клиентов.

В следующем примере показаны основы:

  1. Создать Selector
  2. Создание SocketChannel
  3. Зарегистрируйте SocketChannel для Selector
  4. Цикл с 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


Modified text is an extract of the original Stack Overflow Documentation
Лицензировано согласно CC BY-SA 3.0
Не связан с Stack Overflow