1. 程式人生 > >主機位元組序 與 網路位元組序

主機位元組序 與 網路位元組序

一、位元組順序

是指佔用記憶體多於一個位元組型別的資料在記憶體中的存放順序。

計算機電路先處理低位位元組,效率比較高,因為計算都是從低位開始的。所以,計算機的內部處理都是小端位元組序。

但是,網路傳輸、檔案儲存、人類讀寫習慣使用大端位元組序。

  java中一個int型資料佔用4個位元組,假如有一個16進位制的int數,int value =(高位元組) 0x01020304 (低位元組)

小端位元組序(little endian):低位元組資料存放在記憶體低地址

大端位元組序(bigendian): 低位元組資料存放在高地址處

 

主機位元組序跟CPU有關的,IA架構(Intel、AMD)的CPU中是Little-Endian

所謂的JAVA位元組序指的是在JAVA虛擬機器中多位元組型別資料的存放順序,JAVA位元組序也是BIG-ENDIAN。

由於JVM會根據底層的作業系統和CPU自動進行位元組序的轉換,

所以我們使用java進行網路程式設計,幾乎感覺不到位元組序的存在。

  

二、ByteBuffer 示例

複製程式碼

public static void byteOrder() {

        int x = 0x01020304;

        ByteBuffer bb = ByteBuffer.wrap(new byte[4]);
        bb.asIntBuffer().put(x);
        System.out.println( bb.order() +  " 記憶體資料 " +  Arrays.toString(bb.array()));

        bb.order(ByteOrder.LITTLE_ENDIAN);
        bb.asIntBuffer().put(x);
        System.out.println( bb.order() +    " 記憶體資料 " +  Arrays.toString(bb.array()));
    }

複製程式碼

BIG_ENDIAN 記憶體資料 [1, 2, 3, 4]
LITTLE_ENDIAN 記憶體資料 [4, 3, 2, 1]

 

三、Java 與 JavaScript 位元組轉換

如果通訊的雙方都是Java,則根本不用考慮位元組序的問題了。 

Java 的 byte 範圍是[-128, 127],

JavaScript 的 byte 範圍是[0, 256]

 

四、int 與 byte Array 轉換示例

轉換時使用相同的位元組序

複製程式碼

    // 生成4個位元組的網路位元組序,網路傳輸使用大端位元組序,相當於int2ByteArray
    byte[] getNetworkBytesOrder(int sourceNumber) {
        byte[] orderBytes = new byte[4];
        orderBytes[3] = (byte) (sourceNumber & 0xFF);
        orderBytes[2] = (byte) (sourceNumber >> 8 & 0xFF);
        orderBytes[1] = (byte) (sourceNumber >> 16 & 0xFF);
        orderBytes[0] = (byte) (sourceNumber >> 24 & 0xFF);
        return orderBytes;
    }

    // 還原4個位元組的網路位元組序, 相當於byteArray2Int
    int recoverNetworkBytesOrder(byte[] orderBytes) {
        int sourceNumber = 0;
        for (int i = 0; i < 4; i++) {
            sourceNumber <<= 8;
            sourceNumber |= orderBytes[i] & 0xff;
        }
        return sourceNumber;
    }

複製程式碼

 

複製程式碼

        System.out.println(Arrays.toString(intToByteArray(32)));
        System.out.println(Arrays.toString(intToByteArray(145)));
        System.out.println(Arrays.toString(intToByteArray(256)));

        System.out.println(Arrays.toString(intToByteArray2(32)));
        System.out.println(Arrays.toString(intToByteArray2(145)));
        System.out.println(Arrays.toString(intToByteArray2(256)));
       
        //還原
        System.out.println(byteArrayToInt2(intToByteArray2(145)));
        System.out.println(byteArrayToInt(intToByteArray2(145)));

複製程式碼

 

輸出

[0, 0, 0, 32]
[0, 0, 0, -111]
[0, 0, 1, 0]
[0, 0, 0, 32]
[0, 0, 0, -111]
[0, 0, 1, 0]
145
145

複製程式碼

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

    public static byte[] intToByteArray2(int i) {
        return ByteBuffer
                .allocate(4)
//                預設大端位元組序
//                .order(ByteOrder.LITTLE_ENDIAN)
                .putInt(i)
                .array();
    }


    public static int byteArrayToInt2(byte[] byteArray) {
        int value = 0;
        for (int i = 0; i < 4; i++) {
            int shift = (4 - 1 - i) * 8;
            value += (byteArray[i] & 0x000000FF) << shift;
        }
        return value;
    }

    public static int byteArrayToInt(byte [] byteArray){
        return ByteBuffer.wrap(byteArray)
//                預設大端位元組序
//                .order(ByteOrder.LITTLE_ENDIAN)
                .getInt();
    }