5

現在、Chrome 拡張機能と通信する Java プログラムを作成しています。通信するには、Chrome ネイティブ メッセージング プロトコルを実装する必要があります。Google Chrome のドキュメントには次のように書かれています。

... 各メッセージは JSON を使用してシリアル化され、UTF-8 でエンコードされ、ネイティブのバイト順で 32 ビットのメッセージ長が前に付けられます。(ソース

これを Java で実装しようとしましたが、実装が正しいはずなのに、メッセージが特定の長さになると問題が発生します。以前のSO回答と質問に基づく私の現在の実装は次のとおりです(例はこちら):

// read the message size from Chrome. This part works correctly.
public static int getInt(char[] bytes) {
    return  (bytes[3]<<24) & 0xff000000|
            (bytes[2]<<16) & 0x00ff0000|
            (bytes[1]<< 8) & 0x0000ff00|
            (bytes[0]<< 0) & 0x000000ff;
}

// transform the length into the 32-bit message length. 
// This part works for small numbers, but does not work for length 2269 for example.
public static String getBytes(int length) {
    return String.format("%c%c%c%c", 
            (char) ( length      & 0xFF),
            (char) ((length>>8)  & 0xFF),
            (char) ((length>>16) & 0xFF),
            (char) ((length>>24) & 0xFF));
}

問題は、Java が文字を実装する方法にあるようです。C のように、通常の文字を期待します。実際には、Java はこれらの文字を unicode-char に変換することがあるようです (または、少なくとも、これまでのところ私の疑いです)。これは、長さ 2269 の Java プログラムからの次の出力 (実際のバイトを表示するために xxd にパイプされます) に反映されています。

0000000: c39d 0800 00                             .....

ただし、予想される出力(pythonを使用):

import struct
struct.pack('I', 2269)
# outputs in interactive mode: '\xdd\x08\x00\x00'

ここで正確に何が起こっているのですか?Java が "0xDD" を "0xC39D" に変換するのはなぜですか? また、getBytes関数が Chrome ネイティブ メッセージングの予期される入力を表すようにするにはどうすればよいですか? 別の言語を使用することはオプションではありません。

4

1 に答える 1

4

Java の Char は自動的に Unicode に変換されます。この使用例の正しい型は ですbyte。これは、自動的に変換されず、正しい値を保持します。したがって、Chrome ネイティブ メッセージング プロトコルの正しい実装は次のようになります。

    public static byte[] getBytes(int length) {
        byte[] bytes = new byte[4];
        bytes[0] = (byte) ( length      & 0xFF);
        bytes[1] = (byte) ((length>>8)  & 0xFF);
        bytes[2] = (byte) ((length>>16) & 0xFF);
        bytes[3] = (byte) ((length>>24) & 0xFF);
        return bytes;
    }

この方法に加えて、長さバイトの計算と出力の間のどこでも文字列を使用しないように注意する必要があります。への出力はSystem.out、次のように実行できます。

    try {
        System.out.write(getBytes(message.length()));
    } catch (IOException ex) {
        ex.printStackTrace();
    }
于 2014-09-02T06:31:03.947 に答える