JavaとC/C++ネットワーク通信時のデータ変換


最近Androidアプリを作りましたが、PC側とsocketでデータを伝える必要があります.PC側はC++で開発されており,伝送を容易にするために送信前にデータをバイト配列に変換する.万事順調だと思っていたが、過程にはいくつかの問題があった.以下は私が出会ったいくつかの問題と解決策で、ここで簡単な記録をして、みんなが出会った後に迅速に解決することができることを望んで、同時に各位の補充の指摘を歓迎します~
Java Socketの受信と送信
まずsocket接続を確立し、そこからInputStreamとOutputStreamを取得します.受信時にSocketのInputStreamをDataInputStreamでパッケージ化し、後で異なるサイズのデータ型を受信しやすいようにしました.送信時にはまずDataOutputStream()でOutputStreamをパッケージ化し、その後異なるデータ型を書き込み、最後にByteArrayOutputStreamパッケージでバイトストリームに変換し、確立したSocketチャネルで送信する.これで次の2つの問題が発生します.
問題1:大規模な問題
PC側デバイスはx 86プラットフォームを使用しており、データは小端フォーマットである.一方、jvm仮想マシンは、JavaでdataInputStreamを呼び出すなどのバイトを読み込む大端フォーマットを採用しています.read()の場合、1バイトを正常に読み出すことができます.ただし、dataInputStreamのようなマルチバイトのデータ型を読み出す.readInt()の場合、サイズ端のデータエラーが発生します.小端フォーマットは低バイトのデータを低アドレス記憶空間に格納し、大端フォーマットは低バイトのデータを高アドレス空間に格納する.これによって、データの地位はちょうど逆転した.
ソリューション
この問題の解決策も比較的容易であり,誤りデータの高い地位をバタフライ交換することで結果を得ることができる.サイズ端フォーマット変換については、shortベースの変換を先に行い、Intデータの高低ビットに対してshortの変換をそれぞれ呼び出すことができます.コードは以下の通りです.
    /** *         * * @param data *     short   * @return     short  */
    private static short swapShortToLittleEndian(short data)
    {
        short ret = (short) ((data << 8) | (data >> 8) & 0x00FF);
        ret = (short) (ret & 0xFFFF);
        return ret;
    }

次にintデータに対して高低16ビットをそれぞれ以上の変換を行うことができる.
    /** *         * * @param data *     int   * @return     int  */
private static void swapIntToLittleEndian(int data)
    {
        int ret = swapShortToLittleEndian((short) ((data >> 16) & 0xFFFF))
                | (swapShortToLittleEndian((short) data) << 16);
        return ret;
    }

以上の2つの関数により、16バイト、32バイトのデータを小端フォーマットに変換することができ、64ビットについても同様の原理を採用することができる.PS:上记の频繁な0 xFFFF/0 xFF作と演算に疑问を持つ友达がいるかもしれませんが、ここでも2つ目の问题ですが、これは演算と必要です.
質問2:Java暗黙型変換
Javaでは、byteに対する+-*/>>>><&^(プラス、マイナス、乗算、除算、右シフト、左シフト、符号なし右シフト、ビット、ビット、または、ビット異OR)操作は、まずbyteをintに変換し、演算を行います.その後、このプロセスは多くの問題を引き起こす可能性があります.
ソリューション
Javaではデータの扱いを容易にするために,符号数のみが存在することが知られている.すなわち,最上位で符号を表し,残りのビットは実際のデータを表す.上のサイズエンド変換では、まず低8ビットのデータを高8ビットに移動し、高8ビットのデータを低8ビットに移動する必要があります.左シフトの過程で右側が自動補正0であることは間違いなく,直接シフトを行った結果が我々の望む結果となる.でも右に移動すると、正数では(最高位は0)正確な結果も得られるが、負数(最高位は1)であれば、このとき右に移動すると高位が自動的に1を補うので、もちろんこれは演算子「>>」で解決しますが、ここではもう一つの問題があります.byteをシフトすると、システムはそれをintデータに暗黙的に変換し、負数であれば、補完された上位データはすべて1になります.右シフト後に0 xFFとビットを合わせなければ,その後に上位データビットやつなぎ合わせるときに上位が直接1になるのは,なぜ頻繁にビットや操作を行うのかということである.総合:1.JavaでC++符号なしデータを受信する場合は、必ずサイズ端の変換に注意しましょう.2.また、シフト動作に遭遇した場合、右シフト後に高位をクリアしてエラーを解消しなければならないことに注意してください.
以上は個人が直面した問題と自分の解決策で、もしもっと多くの方案があれば、補充を歓迎します!