Java NIOを使用してTCPソケットを使用してC++サーバーに接続するJavaクライアントがあります。これはLinux、AIX、HP/UXで動作しますが、SolarisではOP_CONNECT
イベントは発生しません。Java Solaris NIO OP_CONNECTの問題
さらなる詳細:
Selector.select()
は0を返して、そして '選択キーセット' が空です。- ローカルマシンに(ループバックまたはイーサネットインターフェイス経由で)接続するときにのみ問題が発生しますが、リモートマシンに接続するときには問題が発生します。
- 2つの異なるSolaris 10マシンでこの問題を確認しました。 JDKバージョン1.6.0_21と_26の両方を使用する物理SPARCおよび仮想x64(VMWare)
import java.io.IOException; import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.nio.channels.SelectionKey; import java.nio.channels.Selector; import java.nio.channels.SocketChannel; import java.util.HashSet; import java.util.Iterator; import java.util.Set; public class NioTest3 { public static void main(String[] args) { int i, tcount = 1, open = 0; String[] addr = args[0].split(":"); int port = Integer.parseInt(addr[1]); if (args.length == 2) tcount = Integer.parseInt(args[1]); InetSocketAddress inetaddr = new InetSocketAddress(addr[0], port); try { Selector selector = Selector.open(); SocketChannel channel; for (i = 0; i < tcount; i++) { channel = SocketChannel.open(); channel.configureBlocking(false); channel.register(selector, SelectionKey.OP_CONNECT); channel.connect(inetaddr); } open = tcount; while (open > 0) { int selected = selector.select(); System.out.println("Selected=" + selected); Iterator<SelectionKey> it = selector.selectedKeys().iterator(); while (it.hasNext()) { SelectionKey key = it.next(); it.remove(); channel = (SocketChannel)key.channel(); if (key.isConnectable()) { System.out.println("isConnectable"); if (channel.finishConnect()) { System.out.println(formatAddr(channel) + " connected"); key.interestOps(SelectionKey.OP_WRITE); } } else if (key.isWritable()) { System.out.println(formatAddr(channel) + " isWritable"); String message = formatAddr(channel) + " the quick brown fox jumps over the lazy dog"; ByteBuffer buffer = ByteBuffer.wrap(message.getBytes()); channel.write(buffer); key.interestOps(SelectionKey.OP_READ); } else if (key.isReadable()) { System.out.println(formatAddr(channel) + " isReadable"); ByteBuffer buffer = ByteBuffer.allocate(1024); channel.read(buffer); buffer.flip(); byte[] bytes = new byte[buffer.remaining()]; buffer.get(bytes); String message = new String(bytes); System.out.println(formatAddr(channel) + " read: '" + message + "'"); channel.close(); open--; } } } } catch (IOException e) { e.printStackTrace(); } } static String formatAddr(SocketChannel channel) { return Integer.toString(channel.socket().getLocalPort()); } }
あなたは、このコマンドラインを使用して実行できます:ここで
は、問題を示し、いくつかのテストコードであるあなたはに対して実行している場合、ポートは7でなければならない
java -cp . NioTest3 <ipaddr>:<port> <num-connections>
本物のエコーサービス。すなわち:
java -cp . NioTest3 127.0.0.1:7 5
あなたが実行している本当のエコーサービスを受けることができない場合は、いずれかのソースがhereです。 Solarisの下echoサーバをコンパイルします。
$ cc -o echoserver echoserver.c -lsocket -lnsl
とこのようにそれを実行します。
$ ./echoserver 8007 > out 2>&1 &
これはbugとして日に報告されています。
はい、チャンネルは 'OPEN 'に関心があります。' OP_CONNECT'が 'connect'を呼び出した後で設定されています(そうでなければ' ConnectionPendingException'が発生します)。接続をブロックすると問題が発生します。接続は特別な時間に起こり、他のスレッドのI/Oに干渉すると悪いことになります。 – trojanfoe
@trojanfoe connect()の前にチャンネルを登録してOP_CONNECTに設定する必要があります。そうしないと、イベントを見逃すことがあります。 connect()を呼び出す前にConnectPendingExceptionをスローすることはできません*私は理解しません。その例外の理由はJavadocではかなり明白であり、これはそうではありません。 – EJP
私はその変更を行ってLinuxでテストしましたが(動作しますが)、Solarisでこの問題は修正されません。私は間違った例外を述べた - それはNoConnectionPendingExceptionでしたが、それはもはや起こっていないので、無視してください。 – trojanfoe