Java NIO select()は選択されたキーなしで戻ります-なぜですか?

StackOverflow https://stackoverflow.com/questions/204186

  •  03-07-2019
  •  | 
  •  

質問

いくつかのテストコードを書くと、Selector.select()がSelector.selectedKeys()に処理するキーを含まなくても戻ることができることがわかりました。これは、accept()edチャンネルを登録する際のタイトループで発生しています

SelectionKey.OP_READ | SelectionKey.OP_CONNECT

関心のある操作として。

ドキュメントによると、select()は次の場合に返される必要があります。

1)対処できるチャネルがあります。

2)Selector.wakeup()を明示的に呼び出します-キーが選択されていません。

3)select()を実行するスレッドを明示的にThread.interrupt()します-キーは選択されません。

select()の後にキーが表示されない場合は、(2)と(3)のケースにいる必要があります。ただし、私のコードはこれらのリターンを開始するためにwakeup()またはinterrupt()を呼び出していません。

この振る舞いを引き起こしているのは何か?

役に立ちましたか?

解決

簡単な回答:受け入れられた接続に関心のある操作のリストから OP_CONNECT を削除します-受け入れられた接続は既に接続されています。

私は問題を再現することができました。これはまさにあなたに起こっていることかもしれません:

import java.net.*;
import java.nio.channels.*;


public class MyNioServer {
  public static void main(String[] params) throws Exception {
    final ServerSocketChannel serverChannel = ServerSocketChannel.open();
    serverChannel.configureBlocking(true);
    serverChannel.socket().bind(new InetSocketAddress("localhost", 12345));
    System.out.println("Listening for incoming connections");
    final SocketChannel clientChannel = serverChannel.accept();
    System.out.println("Accepted connection: " + clientChannel);


    final Selector selector = Selector.open();
    clientChannel.configureBlocking(false);
    final SelectionKey clientKey = clientChannel.register(selector, SelectionKey.OP_READ | SelectionKey.OP_CONNECT);
    System.out.println("Selecting...");
    System.out.println(selector.select());
    System.out.println(selector.selectedKeys().size());
    System.out.println(clientKey.readyOps());
  }
}

上記のサーバーが接続を受信すると、接続の最初の select()はブロックせずに終了し、準備完了操作のあるキーはありません。 Javaがこのように振る舞う理由はわかりませんが、多くの人がこの振る舞いに噛まれているようです。

結果は、Windows XP上のSunのJVM 1.5.0_06とLinux 2.6上のSunのJVM 1.5.0_05および1.4.2_04で同じです。

他のヒント

理由は、 OP_CONNECT OP_WRITE は内部で同じものであるため、両方に同時に登録されることはありません( OP_ACCEPT および OP_READ )、およびこの場合のように、チャネルが既に接続されている場合、 OP_CONNECT に登録されることはありません。

>

そして OP_WRITE は、eカーネルのソケット送信バッファーがいっぱいの場合を除いて、ほぼ常に準備ができているため、長さゼロの書き込みを取得した後にのみ登録する必要があります。したがって、すでに接続されているチャンネルを OP_CONNECT に登録することで、 OP_WRITE に実際に登録していたので、 select()がトリガーされました。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top