7

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

SelectionKey.OP_READ | SelectionKey.OP_CONNECT

関心のある操作として。

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

1) 行動できるチャネルがある。

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

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

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

この動作の原因についてのアイデアはありますか?

4

2 に答える 2

9

その理由は、OP_CONNECTOP_WRITEは内部的には同じものであるため、両方 (同上OP_ACCEPTOP_READ) に同時に登録するべきではなくOP_CONNECT、この場合のようにチャネルが既に接続されている場合は、まったく登録すべきではないためです。受け入れられたこと。

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

于 2011-07-11T05:32:05.060 に答える
9

簡単な回答: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 で同じです。

于 2008-10-15T16:13:21.870 に答える