質問
こんにちは、私は単純なJava NIOサーバーを実装しようとしています。そのセレクタとSocketChannelへ登録します。したがって、私はクライアントに耳を傾け、戻っていくつかの応答を送りたいです。たSocketChannelがセレクタに登録された後、クライアント(非NIO)はいくつかのデータを送信した場合でも、サーバは読み取ることができません。まだ繰り返されている生成されたキーをhowerverます。
詳細表示:サーバー側ます:
**First thread**:
公共ボイドラン(){ 一方、(TRUE){
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
serverSocketChannel.configureBlocking(true);
serverSocketChannel.socket().bind(inetAdressOfServer);
SocketChannel clientChannel = serverSocketChannel.accept();
new Listener("").addSocketChannel(clientChannel);
}}
**Second Thread**:
static Selector selector = Selector.open();
public boolean addSocketChannel(SocketChannel clientChannel) {
SelectionKey key = clientSocketChannel.register(selector, selector.OP_READ|SelectionKey.OP_WRITE);
key.attach(new ChannelCallback(clientSocketChannel));
return key.isValid();
}
public void run() {
Set keysSet = selector.keys();
Iterator i = keysSet.iterator();
while (i.hasNext()) {
SelectionKey key = (SelectionKey) i.next();
}
if (key.isReadable()) {
//read and do something
}
}
Client Side:
Socket socket = new Socket(serverIP, serverPort);
DataOutputStream dos = new DataOutputStream(socket.getOutputStream());
dos.writeBytes(str + "\n");
NB:単一のスレッドで実行すると、同じプログラムが動作しますが、上記のように実装された場合、クライアントに耳を傾けていないことになります。 この問題を解決するために私を助けてくださいます。
解決
それはあなたがそこに行っているかを確認することは非常に困難だが、それはあなたが「第二のスレッド」としてマークされてきたものかのように見えます(Runnable
と実際のスレッドを拡張/ Thread
を実装比べていくつかの混乱?)両方のスレッドによって使用されています。特に、私はnew Listener
の構造を推測し、スレッドを開始しています。その後、最初のスレッドでaddSocketChannel
を呼んでいます。そのため、競合状態があります。
また、それはselector
静的を作るために貧しい考えです。
他のヒント
読むにはここでは、別のスレッドからの読み取り動作しますあなたのコードとの明らかな問題です。
public void run() {
Set keysSet = selector.keys();
ので、このセットは常に空になり、セレクタのここでは、イテレータからキーセットを取っているが、ないコードが存在しない、これまでの選択をしている()またはselectNow()。
Iterator i = keysSet.iterator();
while (i.hasNext()) {
SelectionKey key = (SelectionKey) i.next();
}
if (key.isReadable()) {
//read and do something
}
}
これはコンパイルすらしない、キーに「読み取り」のチェックはしばらくの間、ブロック内で行わなければなりません。
SelectionKey key = clientSocketChannel.register(selector,
SelectionKey.OP_READ |
SelectionKey.OP_WRITE);
2つの問題:これが行われると、あなたは鍵は、あなたが選択を実行するたびに返される場合を除き、SelectionKey.OP_WRITEを設定するべきではありません前にチャネルが非ブロックモードに設定する必要があります。
あなたが実際に書き込みを行うことを計画している場合は、あなただけのSelectionKey.OP_WRITEを設定する必要があります。
最後に、ここでは2つのスレッドを使用することは非常に異例です。これを行うための推奨される方法はOP_ACCEPTでセレクタにのServerSocketChannelを登録し、実行するために、読み取りと同じスレッド上でのServerSocketに受け入れる/書き込みされます。