Как я могу проверить, завершился ли SocketChannel.read () для неблокирующего канала? - PullRequest
1 голос
/ 28 февраля 2020

Я использую функцию для чтения байтов из неблокирующего SocketChannel (сокет от accept ()) и из блокирующего SocketChannel (на стороне клиента). Я реализую сервер, используя селектор для обработки нескольких клиентов, и использую адрес обратной связи, чтобы использовать только свой ноутбук. Я написал это

while((r = socketChannel.read(ackBuf)) != -1) {
        System.out.println(name3d+" r: "+r);
    }

, и я ожидал, что когда будет достигнут конец содержимого в канале, read () вернет -1, но это не то, что удастся. read (), в неблокирующей конфигурации, также возвращает 0, если в данный момент ничего не готово к чтению, но это будет в ближайшее время (если я хорошо понимаю), поэтому если я изменю код на

while((r = socketChannel.read(ackBuf)) > 0) {
        System.out.println(name3d+" r: "+r);
    }

I также не прочтет ничего, если что-то будет готово через мгновение. Как я могу различить guish, если я получил 0, потому что не готов или потому что он закончился? В следующем фрагменте я могу во второй раз проверить чтение после сна, но я уверен, что это не надежный способ сделать то, что я хочу.

int times = 0;
while((r = socketChannel.read(ackBuf)) != -1 && times<2) {
    if (r == 0)
        try {
            Thread.sleep(500);
            times++;
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    System.out.println(name3d+" r: "+r);
}

Ответы [ 2 ]

0 голосов
/ 28 февраля 2020

Неблокирующий SocketChannel используется немного по-другому.

  1. Сначала вы ждете, когда клавиша выбора сообщит вам, что есть данные, и
  2. , затем вы читаете эти данные. с канала.

См. черновик этого кода:

  Selector selector = Selector.open();
  SocketChannel sc = SocketChannel.open();
  sc.configureBlocking(false);
  sc.connect(addr);
  sc.register(selector, SelectionKey.OP_READ);
  while (true) {
    // select() can block!
    if (selector.select() == 0) {
      continue;
    }
    Iterator iterator = selector.selectedKeys().iterator();
    while (iterator.hasNext()) {
     SelectionKey key = (SelectionKey) iterator.next();
     iterator.remove();
     if (key.isReadable()) {
       SocketChannel sc = (SocketChannel) key.channel();
       ByteBuffer bb = ByteBuffer.allocate(1024);
       sc.read(bb);
       System.out.println("Message received!");
     }
}
0 голосов
/ 28 февраля 2020

"если я получил 0, потому что не готов или потому что он закончился?" Вы имеете в виду сообщение или совокупность сообщений?

Для сообщения вы должны использовать для связи протокол связи (например, json или http), я думаю, что вы должны получить исключение SocketException ... Если бы вы использовали блокировку, а другой человек закрыл соединение ... (я написал много людей на SO о том, как SocketException ваш друг)

--- edit - -

Просматривая документацию для Channel, похоже, что вы должны получить IOException некоторого вида (SocketException является подклассом IOException), если / когда канал закрыт

...