1

こんにちは私は単純なJavaNIOサーバーを実装しようとしています。これはsocketChannelをセレクターに登録します。したがって、私はクライアントに耳を傾け、いくつかの応答を送り返したいと思います。socketChannelがセレクターに登録された後、クライアント(非NIO)がデータを送信しても、サーバーは読み取ることができません。ただし、生成されたキーはまだ繰り返されています。

詳細ビュー:サーバー側:

**First thread**:

public void run(){while(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");

注意:シングルスレッドで実行すると同じプログラムが機能しますが、上記の方法で実装すると、クライアントをリッスンしなくなります。この問題の解決にご協力ください。

4

2 に答える 2

1

そこで何をしたかを確認するのは非常に困難ですが、「2番目のスレッド」としてマークしたものが両方のスレッドで使用されているように見えます(Runnable/拡張Threadスレッドと実際のスレッドの実装について混乱がありますか?)。特に、new Listener構成を推測してスレッドを開始します。addSocketChannel次に、最初のスレッドで呼び出します。したがって、競合状態があります。

selectorまた、静的にすることはお勧めできません。

于 2009-05-25T12:40:33.413 に答える
1

読み取りは別のスレッドからの読み取りに機能します。コードの明らかな問題は次のとおりです。

public void run() {
    Set keysSet = selector.keys();

ここでは、イテレータからキー セットを取得していますが、セレクタで select() または selectNow() を実行するコードがないため、このセットは常に空になります。

    Iterator i = keysSet.iterator();        
    while (i.hasNext()) {
        SelectionKey key = (SelectionKey) i.next();
    }
    if (key.isReadable()) {
        //read and do something
    }
}

これはコンパイルさえしません。キーの「読み取り」のチェックは、while ブロック内で行う必要があります。

SelectionKey key = clientSocketChannel.register(selector,
                                                SelectionKey.OP_READ | 
                                                SelectionKey.OP_WRITE);              

2 つの問題: これを行う前にチャネルを非ブロッキング モードに設定する必要があります。select を実行するたびにキーを返す必要がない限り、SelectionKey.OP_WRITE を設定しないでください。

実際に書き込みを行う予定がある場合にのみ、SelectionKey.OP_WRITE を設定する必要があります。

最後に、ここで 2 つのスレッドを使用するのは非常に型破りです。これを行うための推奨される方法は、OP_ACCEPT を使用して ServerSocketChannel をセレクターに登録し、読み取り/書き込みと同じスレッドで ServerSocket で受け入れを実行することです。

于 2009-05-25T18:27:37.433 に答える