1

ノンブロッキング ソケット、nio を使用するサーバーがあります。サーバーは別のスレッドで動作し、ゲームと呼ばれる別のスレッドがあります。ゲーム スレッドはサーバー オブジェクトを保持し、server.sendMessage を使用します。サーバー スレッドはデータを読み取るだけです。while ループで 2 つのパケットに対して sendMessage を 2 回連続して呼び出すと、クライアントで「java.io.StreamCorruptedException: 無効なストリーム ヘッダー: 6B6574B4」エラーが発生します。

サーバーコードの一部:

public void write(SelectionKey channelKey, byte[] buffer) {
    if (buffer != null) {
        int bytesWritten;
        try {
            SocketChannel channel = (SocketChannel) channelKey.channel();
            synchronized (channel) {
                bytesWritten = channel.write(ByteBuffer.wrap(buffer));
            }
            if (bytesWritten == -1) {
                resetKey(channelKey);
                disconnected(channelKey);
            }
        } catch (Exception e) {
            resetKey(channelKey);
            disconnected(channelKey);
        }
    }
}

public void broadcast(byte[] buf, SelectionKey fr) {
    synchronized (clientList) {
        Iterator<SelectionKey> i = clientList.iterator();
        while (i.hasNext()) {
            SelectionKey key = i.next();
            if (fr != key)
                write(key, buf);
        }
    }
}

public synchronized void sendMessage(Packets pk) {
    broadcast(pk.toByteArray(), null);
}
4

2 に答える 2

1

私の推測では (あなたが含めた少量のコードから)、メッセージをまったく描写していないということです。2 つのメッセージを別々に送信しても、受信者が前のメッセージに添付された 1 つのメッセージの一部を取得するように、io レイヤーはさまざまな方法でそれらを分割/結合する場合があります。ある種の「メッセージ」プロトコルを使用して、消費する正確なバイト数を受信者に示し、受信メッセージを正しく解析できるようにする必要があります (たとえば、メッセージのバイト長を最初に書き、次にメッセージのバイト数を書きます)。

補足として、write()メソッドは 1 回の呼び出しですべてのバイトを書き込むことが保証されていないため、戻り値を処理し、必要に応じて残りのバイトを書き込む必要があります。

于 2013-05-08T18:20:03.153 に答える
1

flip()書き込みの前と後で行う必要があり、バッファ全体compact()を書き込むと仮定するのをやめる必要があります。write()何らかの理由で値を返します。ループする必要があります。または、非ブロッキング モードの場合は、次のように処理する必要があります。

  1. 書く。
  2. 書き込みが完全に完了していない場合は、チャネルを OP_WRITE に登録し、選択ループに戻ります。
  3. チャネルが書き込み可能になったら、書き込みを再試行します。それでも完了しない場合は、ループを続けます。
  4. それ以外の場合は、OP_WRITE の登録を解除します。
于 2013-05-09T02:16:20.960 に答える