0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

二進(jìn)制通信協(xié)議序列化介紹

jf_78858299 ? 來源: ChinaUnix ? 作者: ChinaUnix raochaoxun ? 2023-02-13 14:49 ? 次閱讀

通信協(xié)議可以理解兩個(gè)節(jié)點(diǎn)之間為了協(xié)同工作實(shí)現(xiàn)信息交換,協(xié)商一定的規(guī)則和約定,例如規(guī)定字節(jié)序,各個(gè)字段類型,使用什么壓縮算法或加密算法等。常見的有tcp,udp,http,sip等常見協(xié)議。協(xié)議有流程規(guī)范和編碼規(guī)范。流程如呼叫流程等信令流程,編碼規(guī)范規(guī)定所有信令和數(shù)據(jù)如何打包/解包。

編碼規(guī)范就是我們通常所說的編解碼,序列化。不光是用在通信工作上,在存儲(chǔ)工作上我們也經(jīng)常用到。如我們經(jīng)常想把內(nèi)存中對(duì)象存放到磁盤上,就需要對(duì)對(duì)象進(jìn)行數(shù)據(jù)序列化工作。

本文采用先循序漸進(jìn),先舉一個(gè)例子,然后不斷提出問題-解決完善,這樣一個(gè)迭代進(jìn)化的方式,介紹一個(gè)協(xié)議逐步進(jìn)化和完善,最后總結(jié)??赐曛?,大家以后在工作就很容易制定和選擇自己的編碼協(xié)議。

緊湊模式

本文例子是A和B通信,獲取或設(shè)置基本資料,一般開發(fā)人員第一步就是定義一個(gè)協(xié)議結(jié)構(gòu):

struct userbase
{
    //1-get, 2-set, 定義一個(gè)short,為了擴(kuò)展更多命令
    unsigned short cmd;

    //1 – man , 2-woman
    unsigned char gender; 

    //當(dāng)然這里可以定義為 string name;或len + value 組合,
        為了敘述方便,就使用簡單定長數(shù)據(jù)
    char name[8]; 
}

在這種方式下,A基本不用編碼,直接從內(nèi)存copy出來,再把cmd做一下網(wǎng)絡(luò)字節(jié)序變換,發(fā)送給B。B也能解析,一切都很和諧愉快。

這時(shí)候編碼結(jié)果可以用圖表示為(1格一個(gè)字節(jié))

圖片

這種編碼方式,我稱之為緊湊模式,意思是除了數(shù)據(jù)本身外,沒有一點(diǎn)額外冗余信息,可以看成是Raw Data。在dos年代,這種使用方式非常普遍,那時(shí)候可是內(nèi)存和網(wǎng)絡(luò)都是按K計(jì)算,cpu還沒有到1G。如果添加額外信息,不光耗費(fèi)捉襟見肘的cpu,連內(nèi)存和帶寬都傷不起。

可擴(kuò)展性

有一天,A在基本資料里面加一個(gè)生日字段,然后告訴B

struct userbase
{
    unsigned short cmd;
    unsigned char gender;
    unsigned int birthday;
    char name[8];
}

這是B就犯愁了,收到A的數(shù)據(jù)包,不知道第3個(gè)字段到底是舊協(xié)議中的name字段,還是新協(xié)議中birthday。這是后A,和B終于從教訓(xùn)中認(rèn)識(shí)到一個(gè)協(xié)議重要特性——兼容性和可擴(kuò)展性。

于是乎,A和B決定廢掉舊的協(xié)議,從新開始,制定一個(gè)以后每個(gè)版本兼容的協(xié)議。方法很簡單,就是加一個(gè)version字段。

struct userbase
{
    unsigned short version;
    unsigned short cmd;
    unsigned char gender;
    unsigned int birthday;
    char name[8];
}

這樣,A和B就松一口氣,以后就可以很方便的擴(kuò)展。增加字段也很方便。這種方法即使在現(xiàn)在,應(yīng)該還有不少人使用。

更好的擴(kuò)展性

過了一段較長時(shí)間,A和B發(fā)現(xiàn)又有新的問題,就是每增加一個(gè)字段就改變一下版本號(hào),這還不是重點(diǎn),重點(diǎn)是這樣代碼維護(hù)起來相當(dāng)麻煩,每個(gè)版本一個(gè)case分支,到了最好,代碼里面case 幾十個(gè)分支,看起來丑陋而且維護(hù)起來成本高。

A 和 B仔細(xì)思考了一下,覺得光靠一個(gè)version維護(hù)整個(gè)協(xié)議,不夠細(xì),于是覺得為每個(gè)字段增加一個(gè)額外信息——tag,雖然增加內(nèi)存和帶寬,但是現(xiàn)在已經(jīng)不像當(dāng)年那樣,可以容許這些冗余,換取易用性。

struct userbase
{
    unsigned short version;
    unsigned short cmd;
    unsigned char gender;
    unsigned int birthday;
    char name[8];
}

圖片

制定完這些協(xié)議后,A和B很得意,覺得這個(gè)協(xié)議不錯(cuò),可以自由的增加和減少字段。隨便擴(kuò)展。

現(xiàn)實(shí)總是很殘酷的,不久就有新的需求,name使用8個(gè)字節(jié)不夠,最大長度可能會(huì)達(dá)到100個(gè)字節(jié),A和B就愁懷了,總不能即使叫“steven”的人,每次都按照100個(gè)字節(jié)打包,雖然不差錢,也不能這樣浪費(fèi)。

于是A和B尋找各方資料,找到了ANS.1編碼規(guī)范,好東西啊.. ASN.1是一種ISO/ITU-T 標(biāo)準(zhǔn)。其中一種編碼BER(Basic Encoding Rules)簡單好用,它使用三元組編碼,簡稱TLV編碼。

每個(gè)字段編碼后內(nèi)存組織如下

圖片

字段可以是結(jié)構(gòu),即可以嵌套

圖片

A和B使用TLV打包協(xié)議后,數(shù)據(jù)內(nèi)存組織大概如下:

圖片

TLV具備了很好可擴(kuò)展性,很簡單易學(xué)。同時(shí)也具備了缺點(diǎn),因?yàn)槠湓黾恿?個(gè)額外的冗余信息,tag 和len,特別是如果協(xié)議大部分是基本數(shù)據(jù)類型int ,short, byte. 會(huì)浪費(fèi)幾倍存儲(chǔ)空間。另外Value具體是什么含義,需要通信雙方事先得到描述文檔,即TLV不具備結(jié)構(gòu)化和自解釋特性。

自解釋性

當(dāng)A和B采用TLV協(xié)議后,似乎問題都解決了。但是還是覺得不是很完美,決定增加自解釋特性,這樣抓包就能知道各個(gè)字段類型,不用看協(xié)議描述文檔。這種改進(jìn)的類型就是 TT[L]V(tag,type,length,value),其中L在type是定長的基本數(shù)據(jù)類型如int,short, long, byte時(shí)候,因?yàn)槠溟L度是已知的,所以L不需要。

于是定義了一些type值如下

圖片

按照ttlv序列化后,內(nèi)存組織如下

圖片

改完后,A和B發(fā)現(xiàn),的確帶來很多好處,不光可以隨心所以的增刪字段,還可以修改數(shù)據(jù)類型,例如把cmd改成int cmd;可以無縫兼容。真是太給力了。

跨語言特性

有一天來了一個(gè)新的同事C,他寫一個(gè)新的服務(wù),需要和A通信,但是C是用java或PHP的語言,沒有無符號(hào)類型,導(dǎo)致負(fù)數(shù)解析失敗。為了解決這個(gè)問題,A重新規(guī)劃一下協(xié)議類型,做了有些剝離語言特性,定義一些共性。對(duì)使用類型做了強(qiáng)制性約束。雖然帶來了約束,但是帶來通用型和簡潔性,和跨語言性,大家表示都很贊同,于是有了一個(gè)類型(type)規(guī)范。

圖片

代碼自動(dòng)化

但是A和B發(fā)現(xiàn)了新的煩惱,就是每搞一套新的協(xié)議,都要從頭編解碼,調(diào)試,雖然TLV很簡單,但是寫編解碼是一個(gè)毫無技術(shù)含量的枯燥體力活,一個(gè)非常明顯的問題是,由于大量copy/past,不管是對(duì)新手還是老手,非常容易犯錯(cuò),一犯錯(cuò),定位排錯(cuò)非常耗時(shí)。于是A想到使用工具自動(dòng)生成代碼。

IDL(Interface Description Language),它是一種描述語言,也是一個(gè)中間語言,IDL一個(gè)使命就是規(guī)范和約束,就像前面提到,規(guī)范使用類型,提供跨語言特性。通過工具分析idl文件,生成各種語言代碼

Gencpp.exe sample.idl 輸出 sample.cpp sample.h

Genphp.exe sample.idl 輸出 sample.php

Genjava.exe sample.idl 輸出 sample.java

是不是簡單高效。

總結(jié)

大家看到這里,是不是覺得很面熟。是的,協(xié)議講到最后,其實(shí)就是和facebook的thrift和google protocol buffer協(xié)議大同小異了。包括公司無線使用的jce協(xié)議。咋一看這些協(xié)議的idl文件,發(fā)現(xiàn)幾乎是一樣的。只是有些細(xì)小差異化。

這些協(xié)議在一些細(xì)節(jié)上增加了一些特性:

1、 壓縮,這里壓縮不是指gzip之類通用壓縮,是指針對(duì)整數(shù)壓縮,如int類型,很多情況下值是小于127(值為0的情況特別多),就不需要占用4個(gè)字節(jié),所以這些協(xié)議做了一些細(xì)化處理,把int類型按照情況,只使用1/2/3/4字節(jié),實(shí)際上還是一種ttlv協(xié)議。

2、 reuire/option 特性: 這個(gè)特性有兩個(gè)作用,1、還是壓縮,有時(shí)候一個(gè)協(xié)議很多字段,有些字段可以帶上也可以不帶上,不賦值的時(shí)候不是也要帶一個(gè)缺省值打包,這樣很浪費(fèi),如果字段是option特性,沒有賦值的話,就不用打包。2、有點(diǎn)邏輯上約束功能,規(guī)定哪些字段必須有,加強(qiáng)校驗(yàn)。

序列化是通信協(xié)議的基礎(chǔ),不管是信令通道還是數(shù)據(jù)通道,還是rpc,都需要使用到。在設(shè)計(jì)協(xié)議早期就考慮到擴(kuò)展性和跨語言特性。會(huì)為以后省去不少麻煩。

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • 通信協(xié)議
    +關(guān)注

    關(guān)注

    28

    文章

    911

    瀏覽量

    40403
  • 二進(jìn)制
    +關(guān)注

    關(guān)注

    2

    文章

    796

    瀏覽量

    41741
  • TCP
    TCP
    +關(guān)注

    關(guān)注

    8

    文章

    1378

    瀏覽量

    79224
  • UDP
    UDP
    +關(guān)注

    關(guān)注

    0

    文章

    327

    瀏覽量

    34018
收藏 人收藏

    評(píng)論

    相關(guān)推薦

    二進(jìn)制相對(duì)調(diào)相(二進(jìn)制差分調(diào)相2DPSK)的工作原理

    二進(jìn)制相對(duì)調(diào)相(二進(jìn)制差分調(diào)相2DPSK)的工作原理
    發(fā)表于 10-21 13:01 ?3213次閱讀
    <b class='flag-5'>二進(jìn)制</b>相對(duì)調(diào)相(<b class='flag-5'>二進(jìn)制</b>差分調(diào)相2DPSK)的工作原理

    二進(jìn)制

    二進(jìn)制   二進(jìn)制與十進(jìn)制的區(qū)別在于數(shù)碼的個(gè)數(shù)和進(jìn)位規(guī)律有很大的區(qū)別,顧名思義,二進(jìn)制的計(jì)數(shù)規(guī)律為逢二進(jìn)一,是以2為基數(shù)的計(jì)數(shù)體制。10這
    發(fā)表于 04-06 23:48 ?8236次閱讀
    <b class='flag-5'>二進(jìn)制</b>

    二進(jìn)制時(shí)鐘電路

    二進(jìn)制時(shí)鐘電路
    發(fā)表于 09-11 11:22 ?3135次閱讀
    <b class='flag-5'>二進(jìn)制</b>時(shí)鐘電路

    二進(jìn)制編碼和二進(jìn)制數(shù)據(jù)

    二進(jìn)制編碼和二進(jìn)制數(shù)據(jù)   二進(jìn)制編碼是計(jì)算機(jī)內(nèi)使用最多的碼制,它只使用兩個(gè)基本符號(hào)"0"和"1",并且通過由這兩個(gè)符號(hào)組成的
    發(fā)表于 10-13 16:22 ?4817次閱讀

    什么是二進(jìn)制計(jì)數(shù)器,二進(jìn)制計(jì)數(shù)器原理是什么?

    什么是二進(jìn)制計(jì)數(shù)器,二進(jìn)制計(jì)數(shù)器原理是什么? 計(jì)數(shù)器是數(shù)字系統(tǒng)中用得較多的基本邏輯器件。它不僅能記錄輸入時(shí)鐘脈沖的個(gè)數(shù),還可以實(shí)現(xiàn)
    發(fā)表于 03-08 13:16 ?3.1w次閱讀

    二進(jìn)制電平,什么是二進(jìn)制電平

    二進(jìn)制電平,什么是二進(jìn)制電平 在二進(jìn)制數(shù)字通信系統(tǒng)中,每個(gè)碼元或每個(gè)符號(hào)只能是“1”和“0”兩個(gè)狀態(tài)之一。若將每個(gè)碼元可能取的狀態(tài)增
    發(fā)表于 03-17 16:51 ?2370次閱讀

    二進(jìn)制加法程序【匯編版】

    二進(jìn)制加法程序【匯編版】二進(jìn)制加法程序【匯編版】二進(jìn)制加法程序【匯編版】二進(jìn)制加法程序【匯編版】
    發(fā)表于 12-29 11:02 ?0次下載

    二進(jìn)制加法程序【C語言版】

    二進(jìn)制加法程序【C語言版】二進(jìn)制加法程序【C語言版】二進(jìn)制加法程序【C語言版】二進(jìn)制加法程序【C語言版】
    發(fā)表于 12-29 11:03 ?0次下載

    LabVIEW二進(jìn)制數(shù)組轉(zhuǎn)換二進(jìn)制字符串的詳細(xì)資料免費(fèi)下載

    本文檔的主要內(nèi)容詳細(xì)介紹的是LabVIEW二進(jìn)制數(shù)組轉(zhuǎn)換二進(jìn)制字符串的詳細(xì)資料免費(fèi)下載,需要的下載吧。
    發(fā)表于 11-29 08:00 ?16次下載
    LabVIEW<b class='flag-5'>二進(jìn)制</b>數(shù)組轉(zhuǎn)換<b class='flag-5'>二進(jìn)制</b>字符串的詳細(xì)資料免費(fèi)下載

    一種面向私有二進(jìn)制協(xié)議的報(bào)文聚類方法

    報(bào)文聚類是協(xié)議逆向工程的主要步驟之一。針對(duì)私有二進(jìn)制協(xié)議報(bào)文,目前的報(bào)文聚類方法存在報(bào)文向量化特征冗余的問題,而且傳統(tǒng)聚類方法存在聚類中心和聚類簇?cái)?shù)難以確定的問題。根據(jù)n-gram序列化
    發(fā)表于 04-12 11:04 ?9次下載
    一種面向私有<b class='flag-5'>二進(jìn)制</b><b class='flag-5'>協(xié)議</b>的報(bào)文聚類方法

    一種全新的未知二進(jìn)制協(xié)議格式推斷方法

    層次聚類,以CH( Calinski- Harabasz)系數(shù)為評(píng)價(jià)標(biāo)準(zhǔn)獲得最優(yōu)聚類,通過對(duì)聚類所得結(jié)果進(jìn)行改進(jìn)的序列對(duì)比以獲得帶有間隔的協(xié)議數(shù)據(jù)序列,統(tǒng)計(jì)合并連續(xù)間隔,以分析協(xié)議格式
    發(fā)表于 05-18 11:21 ?4次下載

    一種全新的未知二進(jìn)制協(xié)議格式推斷方法

    層次聚類,以CH( Calinski- Harabasz)系數(shù)為評(píng)價(jià)標(biāo)準(zhǔn)獲得最優(yōu)聚類,通過對(duì)聚類所得結(jié)果進(jìn)行改進(jìn)的序列對(duì)比以獲得帶有間隔的協(xié)議數(shù)據(jù)序列,統(tǒng)計(jì)合并連續(xù)間隔,以分析協(xié)議格式
    發(fā)表于 05-18 11:21 ?1次下載

    C#實(shí)現(xiàn)對(duì)象序列化的三種方式是什么

    很多小伙伴一提到序列化,都會(huì)想到二進(jìn)制序列化,但其實(shí)序列化并不僅僅只是二進(jìn)制序列化,我們常說的對(duì)
    的頭像 發(fā)表于 02-22 16:11 ?1249次閱讀
    C#實(shí)現(xiàn)對(duì)象<b class='flag-5'>序列化</b>的三種方式是什么

    什么是序列化 為什么要序列化

    ”(Deserialization )。 雖然掛著機(jī)器人的羊頭,但是后面的介紹全部是計(jì)算機(jī)知識(shí),跟機(jī)器人一丁點(diǎn)關(guān)系都沒有,序列化就是一個(gè)純粹的計(jì)算機(jī)概念。 序列化的英文Serialize就有把一個(gè)東西變成一串連續(xù)的東西之意。 形
    的頭像 發(fā)表于 09-14 17:22 ?2662次閱讀
    什么是<b class='flag-5'>序列化</b> 為什么要<b class='flag-5'>序列化</b>

    二進(jìn)制DAC示例介紹

    電子發(fā)燒友網(wǎng)站提供《二進(jìn)制DAC示例介紹.pdf》資料免費(fèi)下載
    發(fā)表于 11-28 11:23 ?1次下載
    <b class='flag-5'>二進(jìn)制</b>DAC示例<b class='flag-5'>介紹</b>