0

作業中のアプリケーションのサーバー コンポーネントを作成しています。ネットワークを処理するために NIO を使用していますが、読み取りを処理する効率的な方法を見つけるのに苦労しています。クライアント アプリケーションは、サイズが大きく異なるパケットをサーバーに送信できます。100 バイトのテキスト メッセージまたは 500 キロバイトの画像である可能性があり、サーバーはこれらのパケットを処理できる必要があります。通常、考えられる最大のパケットを格納するのに十分な大きさのバッファーを作成しますが、このアプリケーションの場合、メガバイトのバッファーが必要になる場合があります。クライアントごとにサイズが異なり、メモリをむさぼり食います。友人と話し合った結果、古い IO を使用していた場合と同じように処理することにしました。これは、パケットごとに新しいバッファを割り当てることを意味します。バッファの容量は、着信パケットの長さとまったく同じです。私のパケット構造は次のとおりです。

[整数] [長さ]
[バイト] [オペコード]
[バイト...] [ペイロード]

私のアプローチは、長さを読み取るための容量が 4 の 1 つのバッファーと、別の容量 (パケットの長さ) で常に再初期化される別のバッファーの 2 つの別個のバッファーを用意することです。これが私が思いついたコードです:

User user = (User) selectionKey.attachment();
SocketChannel socketChannel = user.getSocketChannel();
ByteBuffer readBuffer = user.getReadBuffer();
ByteBuffer lengthBuffer = user.getLengthBuffer();
/*
 * Read as many packets as possible.
 */
while (true) {
    /*
     * Read the length if it has not been read yet.
     */
    if (lengthBuffer.hasRemaining()) {
    socketChannel.read(lengthBuffer);
    /*
     * If the length could not be read, stop reading and wait for
     * more data to arrive.
     */
    if (lengthBuffer.hasRemaining()) {
        break;
    }
    } else {
    /*
     * Create a read buffer if one has not been created for the
     * incoming packet.
     */
    if (readBuffer == null) {
        lengthBuffer.flip();
        user.setReadBuffer(ByteBuffer.allocate(lengthBuffer
            .getInt()));
    }
    /*
     * Attempt to read the packet.
     */
    socketChannel.read(readBuffer);
    /*
     * If the packet was not completely read, then stop reading
     * altogether because all of the data has not been received yet.
     */
    if (readBuffer.hasRemaining()) {
        break;
    } else {
        /*
         * Otherwise, handle the data and prepare the buffers for
         * the next packet read.
         */
        readBuffer.flip();
        user.handleData();
        user.setReadBuffer(null);
        lengthBuffer.clear();
    }
    }
}

そして、これにはいくつかの問題があります。1 つには、行で NullPointerException が発生することがありますsocketChannel.read(readBuffer)。それに加えて、このソリューションはきれいに見えません。コードにロジックが多すぎて問題があるように感じます。誰かが私にいくつかの変更、私のコード、または別のアプローチを提供してくれませんか? 私はそれを感謝します。ありがとう。

余談ですが、Eclipse からコードをここに貼り付けて適切にフォーマットする良い方法をコメントに投稿できますか? 私はコード ボタンを使用していますが、おそらくお気付きのように、インデントが正しくありません。

4

2 に答える 2

0

netty フレームワークを使用することをお勧めします。この種の問題を処理するメカニズムがすでにあるためです。これを見てください

于 2013-04-02T17:41:06.963 に答える