13

2種類のデータ(ポート80とポート81)を2つのポートでリッスンする必要があるソケットリスナーに取り組んでいます。これらのデータは、データに対して実行される操作の種類と非常に似ていますが、異なるポートに到達するため、単に異なります。私は先に進み、Java の ServerSocket クラスを使用して実装をコーディングしましたが、後で ServerSocket クラスの accept() メソッドがブロックであり、私の実装ではそれができないことに気付きました。だから今、私は Java NIO を使用して同じことを実装することを考えていましたが、いくつかのチュートリアルを行った後、私が始めた方法よりも混乱していると思います。ここの誰かが、疑似コードや技術的な「次に何をすべきか」であっても、プロセス全体を順を追って説明してくれるとうれしいです。これが私が達成しようと計画していることです。

2つの同様のスレッドを呼び出すことにより、2つのポートでこれまでと同じようにリッスンします。(非ブロッキング) あるネットワークロケーションからのリモートデバイスが接続し、データを送信してから切断します。

NIO を使用して、localhost のポート 80 などのポートでリッスンするようにサーバーをセットアップする方法についての知識だけが得られれば、残りはすべて非常に簡単に実装できると思います。

乾杯

4

3 に答える 3

15

ここでは、NIO を使い始めるための小さな例を示します。

これは、ポート 80 および 81 でリッスンし、受信したすべてを標準出力に出力するサーバーです。で始まるパケットを受信すると、接続が閉じられCLOSEます。で始まるパケットを受信した後、サーバー全体がシャットダウンされますQUIT。送信部分が欠落しており、エラー処理が少し改善される可能性があります。:-)

public static void main() throws IOException {
    ByteBuffer buffer = ByteBuffer.allocate(1024);
    Selector selector = Selector.open();

    ServerSocketChannel server1 = ServerSocketChannel.open();
    server1.configureBlocking(false);
    server1.socket().bind(new InetSocketAddress(80));
    server1.register(selector, OP_ACCEPT);

    ServerSocketChannel server2 = ServerSocketChannel.open();
    server2.configureBlocking(false);
    server2.socket().bind(new InetSocketAddress(81));
    server2.register(selector, OP_ACCEPT);

    while (true) {
        selector.select();
        Iterator<SelectionKey> iter = selector.selectedKeys().iterator();
        while (iter.hasNext()) {
            SocketChannel client;
            SelectionKey key = iter.next();
            iter.remove();

            switch (key.readyOps()) {
                case OP_ACCEPT:
                    client = ((ServerSocketChannel) key.channel()).accept();
                    client.configureBlocking(false);
                    client.register(selector, OP_READ);
                    break;
                case OP_READ:
                    client = (SocketChannel) key.channel();
                    buffer.clear();
                    if (client.read(buffer) != -1) {
                        buffer.flip();
                        String line = new String(buffer.array(), buffer.position(), buffer.remaining());
                        System.out.println(line);
                        if (line.startsWith("CLOSE")) {
                            client.close();
                        } else if (line.startsWith("QUIT")) {
                            for (SelectionKey k : selector.keys()) {
                                k.cancel();
                                k.channel().close();
                            }
                            selector.close();
                            return;
                        }
                    } else {
                        key.cancel();
                    }
                    break;
                default:
                    System.out.println("unhandled " + key.readyOps());
                    break;
            }
        }
    }
}

ObsSelectionKey : ( OP_ACCEPT...)のフィールドは静的にインポートされます:

import static java.nio.channels.SelectionKey.*;
于 2010-01-23T18:47:12.347 に答える
8

Apache MINANettyなどの多くのフレームワークは、ノンブロッキング IO プログラミングを強化するために Java NIO に基づいて実装されています。NIO プログラミングを悪夢ではなく楽しいものにすることを強くお勧めします。それらはあなたの問題に適合します。

さらに、トランスポート メッセージのサイズとエンコード/デコード (シリアル化/逆シリアル化) のパフォーマンスの両方で効率的なプロトコルを使用するようにしてください。Google Protocol Buffersは、この分野で信頼できるソリューションです。KryoとKryoNetもご覧ください。それらは役に立ちます。

于 2010-01-23T06:30:14.283 に答える
7

NIO は、何千もの同時接続に拡張する必要がある場合に必要です。

それ以外の場合は、複数のスレッドを使用することをお勧めします。各ポート (および対応する) に対して、ループ内ServerSocketで呼び出すスレッドを作成します。accept()これらの呼び出しはブロックされますが、他のスレッドが実行されており、利用可能なタスクを処理しているため問題ありません。

新しいSocketものが受け入れられたら、その接続専用の別のスレッドを作成します。アプリケーションによって異なりますが、通常、このスレッドはソケットから読み取り (ブロック操作)、要求された操作を実行し、結果をソケットに書き込みます。

このアーキテクチャは、ほとんどのデスクトップ プラットフォームで何百もの接続に拡張できます。また、プログラミング モデルは、各接続が自己完結型であり、他の接続から独立している限り、かなり単純です (これにより、同時実行の問題が回避されます)。NIO を導入するとスケーラビリティが向上しますが、多くの複雑さが必要になります。

于 2010-01-23T05:45:50.127 に答える