3

ログ メッセージを GZIP でエンコードし、UDP で送信する必要があるログ システムを実装しています。

私がこれまでに持っているものは次のとおりです。

初期化:

DatagramSocket sock = new DatagramSocket(); 
baos = new ByteArrayOutputStream();
printStream = new PrintStream(new GZIPOutputStream(baos));

この printStream はロガーから渡されます - メッセージはそれを介して到着します

次に、メッセージが到着するたびに:

byte[] d = baos.toByteArray();
DatagramPacket dp = new DatagramPacket(d,d.length,host,port);
sock.send(dp);

現在私が困惑しているのは、ByteArrayOutputStream からデータを削除する方法が見つからないことです (toByteArray() はコピーのみを取得します)。3 つのストリーム オブジェクトすべてを毎回再作成するのは非効率的ではないかと心配しています。

送信されたデータをストリームから削除する方法はありますか? それとも、まったく別の方向に目を向けるべきですか?

4

3 に答える 3

1

速度が重要な場合は、GZIP を使用すると役立つことを確認する価値があります。(多少のレイテンシーが追加されます)

public static void main(String... args) throws IOException {
    test("Hello World");
    test("Nov 20, 2012 4:55:11 PM Main main\n" +
            "INFO: Hello World log message");
}

private static void test(String s) throws IOException {
    byte[] bytes = s.getBytes("UTF-8");
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    GZIPOutputStream outputStream = new GZIPOutputStream(baos);
    outputStream.write(bytes);
    outputStream.close();
    byte[] bytes2 = baos.toByteArray();
    System.out.println("'" + s + "' raw.length=" + bytes.length + " gzip.length=" + bytes2.length);
}

版画

'Hello World' raw.length=11 gzip.length=31
'Nov 20, 2012 4:55:11 PM Main main
INFO: Hello World log message' raw.length=63 gzip.length=80
于 2012-11-20T16:55:26.087 に答える
1

メッセージごとに新しいストリームを作成する必要があります。そうしないと、 を呼び出すたびに、toByteArray()以前のすべてのメッセージが再度送信されます。

より良いアプローチは、おそらくOutputStreamTCP ソケットの を でラップすることですGZIPOutputStream:

printStream = new PrintStream(new GZIPOutputStream(sock.getOutputStream()));

PrintStreamまた、すべてのメッセージの後にフラッシュすることを忘れないでください。そうしないと、何も起こりません。

速度が本当に重要な場合はDatagramChannel、古い (遅い) Steam API の代わりに を使用することを検討する必要があります。これで始められるはずです:

ByteBuffer buffer = ByteBuffer.allocate( 1000 );
ByteBufferOutputStream bufferOutput = new ByteBufferOutputStream( buffer );
GZIPOutputStream output = new GZIPOutputStream( bufferOutput );
OutputStreamWriter writer = new OutputStreamWriter( output, "UTF-8" );
writer.write( "log message\n" );
writer.close();

sock.getChannel().open(); // do this once
sock.getChannel().write( buffer ); // Send compressed data

注:bufferを巻き戻して再利用できますが、すべてのストリームはメッセージごとに 1 回作成する必要があります。

于 2012-11-20T16:16:43.300 に答える
0

答えは私の問題の他の側面に役立ちましたが、実際の質問については、ByteArrayOutputStream からデータをクリアする方法があります。reset() メソッドがあります。実際にバッファをクリアするわけではありませんが、count プロパティを 0 にリセットして、バッファ内に既にあるデータを無視します。

基になる ByteArrayOutputStream をリセットした後に GZIPOutputStream に書き込むとエラーが発生することに注意してください。そのため、すべてを再利用する方法はまだ見つかっていません。

于 2012-11-21T13:14:06.110 に答える