物聯網專用數據交換格式 CBOR

前言

本文將介紹物聯網領域的 JSON 格式——CBOR,CBOR 是專門爲受限制物聯網終端設計的數據交換格式,該格式輕量間接,可以簡單理解爲二進制形式 JSON 格式。CBOR 格式可以與 COAP 協議組合使用,猶如 HTTP+JSON;另外,CBOR 也是 COSE 的基礎。

CBOR 簡述

CBOR 可分爲 8 個主類型(Major Type),CBOR 格式爲了定義 8 種不同的類型,採用首字節的高 3 位定義主類型。 首字節的低 5 位在不同的主類型表示長度(除主類型 0 和主類型 1),如果長度指示不足,則依次使用後續字節。

wp02J4

無符號整數 an unsigned integer

主類型 0,無符號整數編碼後首字節爲 0b000_XXXXX。爲了表達不同長度的無符號整數,CBOR 格式使用第一個字節的低 5 位表示整數類型

負整數 a negative integer

主類型 1,無符號整數編碼後首字節爲 0b001_XXXXX。負整數的編碼方式與無符號整數相似。
例如:

字節數組 a byte string

主類型 2,字節數組編碼後首字節爲 0b010_XXXXX。爲了表達字節數組長度,如果字符數組的長度小於等於 23,那麼直接使用首字節的低 5 位表示;如果長度大於或等於 24 字節,那麼使用第二個字節表示長度;如果長度大於等於 256 字節,那麼使用第二和第三個字節表示長度。

CBOR 長度說明. png

CBOR 格式中一般採用多字節組合的方式表達長度。CBOR 這樣的長度描述方法便於嵌入式設備使用 C 語言解析 CBOR 格式,節約寶貴的棧空間與堆空間。
例如:

特別注意點

另外在 CBOR 格式編碼錢的字節數組一般採用採用小寫 h 開頭,在單引號中描述 HEX 格式內容,例如

字符串 a text string

主類型 3。字符串類型編碼後首字節爲 0b011_XXXXX。字符串格式與字節數組格式非常相似,只是字節數組格式人類不可讀,而字符格式人類可讀。字符串格式表達長度的方式與字節數組類型相似。
例如:

數組 an array of data items

主類型 4。 數組編碼後首字節爲 0b100_XXXXX。以上四種均爲基礎格式,而數組爲一種符合,還可以與自身或其他類型嵌套。數組中數組元素個數(不是編碼後字節長度)的表達方式與字節數組類型相似。
例如:

特別注意點

在 JSON 類型中,鍵名 Key 必須爲字符串,但是在 CBOR 格式中,鍵名 Key 可以是整數。CBOR 通過這種方式可以節省物聯網終端開銷。

鍵值對 a map of pairs of data items

主類型 5。鍵值對編碼後首字節爲 0b101_XXXXX。鍵值對也是一種符合類型,可以嵌套任意類型。鍵值對類型中鍵值對個數(不是編碼後的字節長度)的表達方式與字節類型表達方式相似。例如

擴展類型

主類型 6。擴展類型編碼後首字節爲 0b110_XXXXX。CBOR 通過增加 Tag 的方式擴展類型,滿足未來的擴展。COSE 規範中通過 CBOR Tag 定義了多種新類型。本文暫不詳細展開擴展類型,僅給出幾個 CBOR 示例

特別說明

在 CBOR 擴展類類型描述中,一般以 Tag 編號開頭,然後在小括號中 () 保存內容,內容可以是任意一種 CBOR 類型。

浮點數與簡單類型

主類型 7。浮點數與簡單類型編碼後首字節爲 0b111_XXXXX。該類型定義了簡單類型,時間類型(Date 和 Time)、大整數(Bignum),10 進制整數(Decimal)等。在主類型 7 中,首字節的高 3 位固定爲 0b111,首字節中低 5 位用於表示子類型。

簡單類型

首字節的低 5 位中 0 到 23 表示簡單類,定義如下:

時間類型

CBOR 體驗

參考依賴

<!-- https://mvnrepository.com/artifact/com.upokecenter/cbor -->
<dependency>
    <groupId>com.upokecenter</groupId>
    <artifactId>cbor</artifactId>
    <version>4.0.0-alpha2</version>
</dependency>

還依賴了兩個參考庫joda-timehexdump

<dependency>
    <groupId>org.lasinger.tools</groupId>
    <artifactId>hexdump</artifactId>
    <version>0.2.0</version>
</dependency>
<dependency>
    <groupId>joda-time</groupId>
    <artifactId>joda-time</artifactId>
    <version>2.10.2</version>
</dependency>

整數相關

    @Test
    public void testInt() {
        CBORObject obj = CBORObject.FromObject(1);
        // 通過控制檯打印
        byte[] bytes = obj.EncodeToBytes();
        String hexString = Hexdump.hexdump(bytes);
        System.out.println(hexString);
    }

    @Test
    public void testInt100() {
        CBORObject obj = CBORObject.FromObject(100);
        // 通過控制檯打印,打印方法省略
    }

    @Test
    public void testIntNegative100() {
        CBORObject obj = CBORObject.FromObject(-100);
        // 通過控制檯打印,打印方法省略
    }

字節數組與字符串

    @Test
    public void testByteArray() {
        int length = 500;
        byte[] testByte = new byte[length];
        for (int i = 0; i < length; i++) {
            testByte[i] = 0x30;
        }
        CBORObject obj = CBORObject.FromObject(testByte);
        // 通過控制檯打印,打印方法省略
    }

    @Test
    public void testString() {
        CBORObject obj = CBORObject.FromObject("IETF");
        // 通過控制檯打印,打印方法省略
    }

    @Test
    public void testLargeString() {
        int length = 24;
        StringBuilder builder = new StringBuilder();

        for (int i = 0; i < length; i++) {
            builder.append("0");
        }

        CBORObject obj = CBORObject.FromObject(builder.toString());
        // 通過控制檯打印,打印方法省略
    }

數組

    @Test
    public void testArray() {
        CBORObject obj = CBORObject.NewArray();

        obj.Add(CBORObject.FromObject(1));
        obj.Add(CBORObject.FromObject(2));
        obj.Add(CBORObject.FromObject(3));
        // 通過控制檯打印,打印方法省略
    }

    @Test
    public void testArray24() {
        CBORObject obj = CBORObject.NewArray();

        obj.Add(CBORObject.FromObject(500));
        obj.Add(CBORObject.FromObject(501));
        obj.Add(CBORObject.FromObject(502));
        // 通過控制檯打印,打印方法省略
    }

    /**
     * 嵌套數組 [1, [2,3], [4,5]]
     */
    @Test
    public void testMultiArray() {
        CBORObject obj = CBORObject.NewArray();
        obj.Add(CBORObject.FromObject(1));

        CBORObject subArray1 = CBORObject.NewArray();
        subArray1.Add(CBORObject.FromObject(2));
        subArray1.Add(CBORObject.FromObject(3));
        obj.Add(subArray1);

        CBORObject subArray2 = CBORObject.NewArray();
        subArray2.Add(CBORObject.FromObject(4));
        subArray2.Add(CBORObject.FromObject(5));
        obj.Add(subArray2);
        // 通過控制檯打印,打印方法省略
    }

    @Test
    public void testLargeArray() {
        CBORObject obj = CBORObject.NewArray();

        int length = 25;
        for (int i = 0; i < length; i++) {
            int temp = i + 100;
            obj.Add(CBORObject.FromObject(temp));
        }
        // 通過控制檯打印,打印方法省略
    }

鍵值對

    @Test
    public void testMap() {
        CBORObject obj = CBORObject.NewMap();

        obj.set(1, CBORObject.FromObject(2));
        obj.set(3, CBORObject.FromObject(4));

        // 通過控制檯打印,打印方法省略
    }

    @Test
    public void testJavaMap() {
        Map<String, Integer> map = new HashMap<>();
        map.put("a", 1);
        map.put("b", 2);

        CBORObject obj = CBORObject.FromObject(map);
        // 通過控制檯打印,打印方法省略
    }

浮點型和簡單類型

    @Test
    public void testTrue() {
        CBORObject obj = CBORObject.FromObject(true);

        byte[] bytes = obj.EncodeToBytes();
        String hexString = Hexdump.hexdump(bytes);
        System.out.println(hexString);
    }

    @Test
    public void testBigDecimal() {
        String decimalString = BigDecimal.valueOf(273.15).toString();
        CBORObject obj = CBORObject.FromObject(EDecimal.FromString(decimalString));
        // 通過控制檯打印,打印方法省略
    }

    @Test
    public void testDateTime() {
        DateTime dt = new DateTime(2013, 3, 21, 20, 04, 0);
        CBORObject obj = CBORObject.FromObject(dt.toDate());
        // 通過控制檯打印,打印方法省略
    }

擴展類型

    @Test
    public void testCBORTag() {
        byte[] array = new byte[] {0x01, 0x02, 0x03, 0x04};
        CBORObject obj = CBORObject.FromObjectAndTag(array, 23);
        System.out.println(obj.toString());

        byte[] bytes = obj.EncodeToBytes();
        String hexString = Hexdump.hexdump(bytes);
        System.out.println(hexString);
    }

總結

參考資料

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://www.jianshu.com/p/76adec5e61f8