物聯(lián)網(wǎng)專用數(shù)據(jù)交換格式CBOR

前言

本文將介紹物聯(lián)網(wǎng)領(lǐng)域的JSON格式——CBOR辛孵,CBOR是專門為受限制物聯(lián)網(wǎng)終端設(shè)計的數(shù)據(jù)交換格式,該格式輕量間接赡磅,可以簡單理解為二進制形式JSON格式魄缚。CBOR格式可以與COAP協(xié)議組合使用,猶如HTTP+JSON仆邓;另外鲜滩,CBOR也是COSE的基礎(chǔ)伴鳖。

CBOR簡述

CBOR可分為8個主類型(Major Type),CBOR格式為了定義8種不同的類型徙硅,采用首字節(jié)的高3位定義主類型榜聂。 首字節(jié)的低5位在不同的主類型表示長度(除主類型0和主類型1),如果長度指示不足嗓蘑,則依次使用后續(xù)字節(jié)须肆。

主類型 名稱 首字節(jié) 簡單說明
主類型0 無符號整數(shù) 0x00或 0x10 基礎(chǔ)類型
主類型1 負整數(shù) 0x20或 0x30 基礎(chǔ)類型
主類型2 字節(jié)數(shù)組 0x40或 0x50 基礎(chǔ)類型
主類型3 字符串 0x60或 0x70 基礎(chǔ)類型
主類型4 數(shù)組 0x80或 0x90 組合類型,可嵌套任意類型
主類型5 鍵值對 0xA0或 0xB0 組合類型桩皿,可嵌套任意類型
主類型6 擴展 0xC0或 0xD0 擴展類型
主類型7 數(shù)組 0xE0或 0xF0 浮點數(shù)與簡單類型

無符號整數(shù) an unsigned integer

主類型0豌汇,無符號整數(shù)編碼后首字節(jié)為0b000_XXXXX。為了表達不同長度的無符號整數(shù)泄隔,CBOR格式使用第一個字節(jié)的低5位表示整數(shù)類型

  • 0b000_11000 uint8_t
  • 0b000_11001 uint16_t
  • 0b000_11010 uint32_t
  • 0b000_11011 uint64_t
    請注意拒贱,無符號整數(shù)0到23直接表達,無需使用整數(shù)類型佛嬉。
    例如:
  • 10 編碼后 0x0A
  • 24 編碼后 0x1818
  • 100 編碼后 0x1864
  • 1000 編碼后 0x1903E8

負整數(shù) a negative integer

主類型1逻澳,無符號整數(shù)編碼后首字節(jié)為0b001_XXXXX。負整數(shù)的編碼方式與無符號整數(shù)相似暖呕。
例如:

  • -10 編碼后 0x29
  • -24 編碼后 0x37
  • -100 編碼后 0x3863
  • -1000 編碼后 0x3903E7

字節(jié)數(shù)組 a byte string

主類型2斜做,字節(jié)數(shù)組編碼后首字節(jié)為0b010_XXXXX。為了表達字節(jié)數(shù)組長度湾揽,如果字符數(shù)組的長度小于等于23瓤逼,那么直接使用首字節(jié)的低5位表示;如果長度大于或等于24字節(jié)库物,那么使用第二個字節(jié)表示長度霸旗;如果長度大于等于256字節(jié),那么使用第二和第三個字節(jié)表示長度艳狐。


CBOR長度說明.png

CBOR格式中一般采用多字節(jié)組合的方式表達長度定硝。CBOR這樣的長度描述方法便于嵌入式設(shè)備使用C語言解析CBOR格式,節(jié)約寶貴的椇聊浚空間與堆空間蔬啡。
例如:

  • HEX格式01020304 編碼后 0x4401020304
  • 長度為23的字節(jié)數(shù)組 編碼后 0x57XX....
  • 長度為24的字節(jié)數(shù)組 編碼后 0x5818XX...
  • 長度為100的字節(jié)數(shù)組 編碼后 0x5901F4XX...
    本質(zhì)來說,CBOR僅為這些原始的字節(jié)數(shù)組增加了一個長度描述镀虐。

特別注意點

另外在CBOR格式編碼錢的字節(jié)數(shù)組一般采用采用小寫h開頭箱蟆,在單引號中描述HEX格式內(nèi)容,例如

  • h'01020304'

字符串 a text string

主類型3刮便。字符串類型編碼后首字節(jié)為0b011_XXXXX空猜。字符串格式與字節(jié)數(shù)組格式非常相似,只是字節(jié)數(shù)組格式人類不可讀,而字符格式人類可讀辈毯。字符串格式表達長度的方式與字節(jié)數(shù)組類型相似坝疼。
例如:

  • "a" 編碼后 0x6161
  • "IETF" 編碼后 0x6449455446
  • 長度為24的字符串 編碼后 0x781830XX...

數(shù)組 an array of data items

主類型4。 數(shù)組編碼后首字節(jié)為0b100_XXXXX谆沃。以上四種均為基礎(chǔ)格式钝凶,而數(shù)組為一種符合,還可以與自身或其他類型嵌套唁影。數(shù)組中數(shù)組元素個數(shù)(不是編碼后字節(jié)長度)的表達方式與字節(jié)數(shù)組類型相似耕陷。
例如:

  • [1,2,3] 編碼后 0x83010203
  • [1,[2,3], [4,5]] 編碼后 0x8301820203820405,此處包括3個數(shù)組据沈,第一個數(shù)組0x83哟沫,表示元素個數(shù)為3,第二個0x82b表示元素個數(shù)為2锌介,第3個編碼后元素個數(shù)為3嗜诀。
    對于數(shù)組部分,RFC7049也有些表述不清的地方孔祸。在主類型無符號整數(shù)中裹虫,若整數(shù)值超過24(0x18),該值將會被CBOR編碼為0x1818融击,所以
  • [24, 25, 26] 編碼后為 0x8318181819181A,不是0x83181818雳窟。
  • [500, 501, 502] 編碼后為0x831901F41901F51901F6尊浪,不是0x8301F401F501F6

特別注意點

在JSON類型中,鍵名Key必須為字符串封救,但是在CBOR格式中拇涤,鍵名Key可以是整數(shù)。CBOR通過這種方式可以節(jié)省物聯(lián)網(wǎng)終端開銷誉结。

鍵值對 a map of pairs of data items

主類型5鹅士。鍵值對編碼后首字節(jié)為0b101_XXXXX。鍵值對也是一種符合類型惩坑,可以嵌套任意類型掉盅。鍵值對類型中鍵值對個數(shù)(不是編碼后的字節(jié)長度)的表達方式與字節(jié)類型表達方式相似。例如

  • {"a":1, "b":[2,3]} 編碼后 0xA26161016162820203以舒, 其中0x616101中 0x616101表示一個鍵值對趾痘,0x6161表示字符串編碼"a", 0x01表示值1蔓钟。其中0x6162820203表示另一個鍵值對永票,0x6162表示字符串編碼"b",0x820203表示一個數(shù)組。
  • {1:2, 3:4} 編碼后 0xA201020304 (還需要分析,JSON中鍵名不能為數(shù)字侣集,而CBOR可以)

擴展類型

主類型6键俱。擴展類型編碼后首字節(jié)為0b110_XXXXX。CBOR通過增加Tag的方式擴展類型世分,滿足未來的擴展编振。COSE規(guī)范中通過CBOR Tag定義了多種新類型。本文暫不詳細展開擴展類型罚攀,僅給出幾個CBOR示例

  • 23(h'01020304') 編碼后 0xd74401020304

特別說明

在CBOR擴展類類型描述中党觅,一般以Tag編號開頭,然后在小括號中()保存內(nèi)容斋泄,內(nèi)容可以是任意一種CBOR類型杯瞻。

浮點數(shù)與簡單類型

主類型7。浮點數(shù)與簡單類型編碼后首字節(jié)為0b111_XXXXX炫掐。該類型定義了簡單類型魁莉,時間類型(Date和Time)、大整數(shù)(Bignum)募胃,10進制整數(shù)(Decimal)等旗唁。在主類型7中,首字節(jié)的高3位固定為0b111痹束,首字節(jié)中低5位用于表示子類型检疫。

簡單類型

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

  • 20 表達False
  • 21 表達True
  • 22 表達Null
  • 23 表達Undefined Value
    所以
  • False 編碼后 0xF4
  • True 編碼后 0xF5
  • Null 編碼后 0xF6

時間類型

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>

整數(shù)相關(guān)

    @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);
        // 通過控制臺打印屎媳,打印方法省略
    }

字節(jié)數(shù)組與字符串

    @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());
        // 通過控制臺打印烛谊,打印方法省略
    }

數(shù)組

    @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));
        // 通過控制臺打印嘉汰,打印方法省略
    }

    /**
     * 嵌套數(shù)組 [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);
    }

總結(jié)

  • CBOR格式是一種帶有明顯長度指示的傳輸協(xié)議攒读,而常用的JSON格式并沒有長度指示。長度指示可以幫助終端設(shè)備在進行CBOR解析時節(jié)約寶貴的堆空間辛友。
  • CBOR格式支持鍵值對形式 Key-Value薄扁,Key可以是整數(shù)剪返,而JSON格式中Key值只能是字符串。
  • CBOR格式中Date邓梅、Time脱盲、Decimal類型解決了物聯(lián)網(wǎng)終端設(shè)備中時間日期與十進制數(shù)表達的問題。

參考資料

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末日缨,一起剝皮案震驚了整個濱河市钱反,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌匣距,老刑警劉巖面哥,帶你破解...
    沈念sama閱讀 219,110評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異毅待,居然都是意外死亡尚卫,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,443評論 3 395
  • 文/潘曉璐 我一進店門尸红,熙熙樓的掌柜王于貴愁眉苦臉地迎上來吱涉,“玉大人,你說我怎么就攤上這事外里≡蹙簦” “怎么了?”我有些...
    開封第一講書人閱讀 165,474評論 0 356
  • 文/不壞的土叔 我叫張陵盅蝗,是天一觀的道長鳖链。 經(jīng)常有香客問我,道長墩莫,這世上最難降的妖魔是什么撒轮? 我笑而不...
    開封第一講書人閱讀 58,881評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮贼穆,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘兰粉。我一直安慰自己故痊,他們只是感情好,可當我...
    茶點故事閱讀 67,902評論 6 392
  • 文/花漫 我一把揭開白布玖姑。 她就那樣靜靜地躺著愕秫,像睡著了一般。 火紅的嫁衣襯著肌膚如雪焰络。 梳的紋絲不亂的頭發(fā)上戴甩,一...
    開封第一講書人閱讀 51,698評論 1 305
  • 那天,我揣著相機與錄音闪彼,去河邊找鬼甜孤。 笑死协饲,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的缴川。 我是一名探鬼主播茉稠,決...
    沈念sama閱讀 40,418評論 3 419
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼把夸!你這毒婦竟也來了而线?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,332評論 0 276
  • 序言:老撾萬榮一對情侶失蹤恋日,失蹤者是張志新(化名)和其女友劉穎膀篮,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體岂膳,經(jīng)...
    沈念sama閱讀 45,796評論 1 316
  • 正文 獨居荒郊野嶺守林人離奇死亡誓竿,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,968評論 3 337
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了闷营。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片烤黍。...
    茶點故事閱讀 40,110評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖傻盟,靈堂內(nèi)的尸體忽然破棺而出速蕊,到底是詐尸還是另有隱情,我是刑警寧澤娘赴,帶...
    沈念sama閱讀 35,792評論 5 346
  • 正文 年R本政府宣布规哲,位于F島的核電站,受9級特大地震影響诽表,放射性物質(zhì)發(fā)生泄漏唉锌。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,455評論 3 331
  • 文/蒙蒙 一竿奏、第九天 我趴在偏房一處隱蔽的房頂上張望袄简。 院中可真熱鬧,春花似錦泛啸、人聲如沸绿语。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,003評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽吕粹。三九已至,卻和暖如春岗仑,著一層夾襖步出監(jiān)牢的瞬間匹耕,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,130評論 1 272
  • 我被黑心中介騙來泰國打工荠雕, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留稳其,地道東北人驶赏。 一個月前我還...
    沈念sama閱讀 48,348評論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像欢际,于是被迫代替她去往敵國和親母市。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,047評論 2 355

推薦閱讀更多精彩內(nèi)容

  • 別欺騙自己了损趋! 偶爾還是會想起你牛奶咖啡-時間的光 隨著你遇到的事兒越來越多患久,做的事越來越多,你會不斷完善與修正原...
  • 1.世界上最美的是心浑槽,最不會說謊的是心蒋失;最容易受傷的是心受傷后好不了的還是心。桐玻。篙挽。。镊靴。铣卡。是否:人類的痛與悲都要心來...
    阿頂爺閱讀 338評論 0 0
  • 柳暗花明又一村 文/潘利偉 最近一段時間一直在為朗誦比賽忙碌著,從孩子們的朗誦內(nèi)容偏竟,到孩子們朗誦時的一字一頓煮落,表...
    我寶超萌萌萌噠閱讀 437評論 0 7
  • 2019-03-29 姓名:李麗 六項精進第496期 利他二組 公司:南京澤朗生物科技有限公司 【日精進打卡第18...
    李麗南京澤朗閱讀 161評論 0 1