TLVのシリアライズ

TLVのシリアライズ

通信プロトコルは、どのような圧縮アルゴリズムまたは暗号化アルゴリズムを使用して、各フィールドタイプ、例えば、二つのノード、特定のネゴシエートルールと規則との間の情報の交換を達成するために一緒に動作するように、所定のバイト順序を理解することができます。共通するのは、その上の共通プロトコルTCP、ウド、HTTP、SIPとしています。契約プロセス仕様とエンコードの仕様。プロセスおよびそのようなコールシグナリングプロセスのような他のプロセスは、符号化仕様は、すべてのシグナリングおよびデータはアンパック/梱包方法。

標準のコーディングは、我々は通常、エンコードとデコード、シリアライズを参照するものです。通信の仕事があるだけでなく、私たちはしばしば、ストレージの使用で働きます。私たちは、多くの場合、ディスクにメモリ内のオブジェクトを保存するとして、あなたはデータのシリアル化の作業をオブジェクトにする必要があります。

本論文では、ステップバイ最初のステップは、例を与え、その後、質問お願いし続けるために - 解決するための完璧な、そのような反復ファッションの進化を、契約が緩やかな進化と改善を紹介し、結論を下しました。それを読んだ後、あなたは簡単に将来的に開発し、職場で自分のエンコーディングプロトコルを選択することができます。

1.コンパクトモード

実施例A及びB本明細書での通信は、基本的な情報を取得または設定し、開発者は、最初のステップは、プロトコルの構造を定義することで、一般的です。

struct userbase {
    unsigned short cmd;     // 1-get, 2-set, 定义一个short,为了扩展更多命令(理想那么丰满)
    unsigned char gender;   // 1 – man , 2-woman, 3 - ??
    char name[8];           // 当然这里可以定义为 string name;或len + value 组合,为了方便叙述使用简单定长
}

このように、基本的な必要性は、Bに送られ、メモリから直接コピーをコードして、cmdをネットワークバイトオーダー変換何かをします Bは、すべてが調和のとれたと喜んで、解決することができます。

この時間は、図の符号化結果で表すことができる(1個のバイトセル)

コンパクトモード構造

呼ばれるこの符号化、コンパクトモードデータ自体に加えて、追加の冗長な情報なしに生データとして見ることができることを意味します。DOS時代に、この使用は、非常に一般的であるが、時間が1GにしないKメモリ及びネットワーク・コンピューティング、CPUを押しています。あなたは、余分な情報を追加する場合だけでなく、伸ばし消費するCPU、メモリ、帯域幅がさえ傷つけるために余裕がされています。

2.スケーラビリティ

そしてある日、で基本情報誕生日プラスフィールド、Bに伝えます

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

それはBに気になる、パケットを受信し、最終的には最初の3つのフィールドを知らない古い契約の名前フィールド、または新規契約の誕生日です。互換性と拡張性 - これはプロトコルの重要な機能を教訓に最終的にはA、Bである、と。

それ以来、古い契約を放棄し、再起動するという決定のAとBは、それぞれのバージョンは、将来の合意の発展と互換性があります。この方法は非常に簡単です、バージョンフィールドを追加することです。

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

したがって、リリーフにAとB、それは容易に拡張することができるからです。フィールドを増やしても非常に便利です。この方法は今でも、使う多くの人々があるはずです。

3.優れたスケーラビリティ

時間の長い期間の後、AとBは、それがバージョン番号を変更するには、フィールドを追加することではない、新しい問題を発見した、これが焦点ではない、フォーカスがコードを維持することで、かなり面倒で、ケースの枝の各バージョンに好ましくは、その場合、いくつかの支店コードは、維持するために醜いとコストがかかるに見えます。

AとBはそれについて慎重に検討し、一人で全体としてバージョンの保守契約を感じるために、十分に詳細ではありませんので、各フィールドの追加情報追加 - 、タグをものの、メモリ帯域幅が、今、その後は異なり、これらを許容できるよう増加使いやすさと引き換えに冗長。

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

スケーラブルなアーキテクチャ-1

これらのプロトコルの開発後、AとBは、フィールドを増減すること自由に、この協定が良好であることを、とても誇りに思っています。さりげなく拡張。
Chouhuaiに現実は常に残酷で、すぐに新たな需要があり、8つのバイトを使用して名前が十分ではありません、100バイトの最大長さに達することがあり、AとB、彼らもあたり、「スティーブン」の人を呼び出すことはできません時間は悪くないお金が、そのような無駄にすることはできません、100 byteパックによるものです。

だから、パーティAとBのデータを探して、私たちはANS.1コーディング標準、良いものを見つけたああ... ASN.1は、ISO / ITU-T標準です。使いやすいBER(基本符号化規則)をコードする、請求は、トリプレットコード、短縮使用TLVエンコーディングを

各フィールドはメモリ構成として符号化されます

Tag | Length | Value

フィールドは、ネスト可能な構造とすることができます

TLV構造

A及びBは、TLVのパケットのプロトコルを使用し、データメモリ編成は、おそらく次のように

スケーラブルなアーキテクチャ-2

TLV 具备了很好可扩展性,很简单易学。同时也具备了缺点,因为其增加了 2 个额外的冗余信息,tag 和 len,特别是如果协议大部分是基本数据类型 int ,short, byte. 会浪费几倍存储空间。另外 Value 具体是什么含义,需要通信双方事先得到描述文档,即 TLV 不具备结构化和自解释特性。

4. 自解释性

当 A 和 B 采用 TLV 协议后,似乎问题都解决了。但是还是觉得不是很完美,决定增加自解释特性,这样抓包就能知道各个字段类型,不用看协议描述文档。这种改进的类型就是 TT[L]V(tag,type,length,value),其中 L 在 type 是定长的基本数据类型如 int,short, long, byte 时候,因为其长度是已知的,所以 L 不需要。

于是定义了一些 type 值如下

类型 Type值 类型描述
bool 1 布尔值
int8 2 带符号的一个字符
uint8 3 带符号的一个字符
int16 4 16位有符号整型
uint16 5 16位无符号整型
int32 6 32位有符号整型
uint32 7 32位无符号整型
...
string 2 字符串或二进制序列
struct 13 自定义的结构,嵌套使用
list 14 有序列表
map 15 无序列表

按照 ttlv 序列化后,内存组织如下

ttlvシーケンス構造

改完后,A 和 B 发现,的确带来很多好处,不光可以随心所以的增删字段,还可以修改数据类型,例如把 cmd 改成 int cmd;可以无缝兼容。真是太给力了。

5. 跨语言特性

有一天来了一个新的同事 C,他写一个新的服务,需要和 A 通信,但是 C 是用 java 或 PHP 的语言,没有无符号类型,导致负数解析失败。为了解决这个问题,A 重新规划一下协议类型,做了有些剥离语言特性,定义一些共性,对使用类型做了强制性约束。虽然带来了约束,但是带来通用型和简洁性,和跨语言性,大家表示都很赞同,于是有了一个类型(type)规范。

类型 Type值 类型描述
bool 1 布尔值
int8 2 带符号的一个字符
int16 3 16位有符号整型
int32 4 32位有符号整型
...
string 2 字符串或二进制序列
struct 13 自定义的结构,嵌套使用
list 14 有序列表
map 15 无序列表

6. 代码自动化:IDL语言

但是 A 和 B 发现了新的烦恼,就是每搞一套新的协议,都要从头编解码,调试,虽然 TLV 很简单,但是写编解码是一个毫无技术含量的枯燥体力活,一个非常明显的问题是,由于大量 copy/past,不管是对新手还是老手,非常容易犯错,一犯错,定位排错非常耗时。于是 A 想到使用工具自动生成代码。

IDL(Interface Description Language),它是一种描述语言,也是一个中间语言,IDL 一个使命就是规范和约束,就像前面提到,规范使用类型,提供跨语言特性。通过工具分析 idl 文件,生成各种语言代码。

Gencpp.exe sample.idl 输出 sample.cpp sample.h
Genphp.exe sample.idl 输出 sample.php
Genjava.exe sample.idl 输出 sample.java

7. 总结

大家看到这里,是不是觉得很面熟。是的,协议讲到最后,其实就是和 facebook 的 thrift 和 google protocol buffer 协议大同小异了。包括公司无线使用的 jce 协议。咋一看这些协议的 idl 文件,发现几乎是一样的。只是有些细小差异化。

这些协议在一些细节上增加了一些特性:

  1. 压缩,这里压缩不是指 gzip 之类通用压缩,是指针对整数压缩,如 int 类型,很多情况下值是小于 127(值为 0 的情况特别多),就不需要占用 4 个字节,所以这些协议做了一些细化处理,把 int 类型按照情况,只使用 1/2/3/4 字节,实际上还是一种 ttlv 协议。

  2. reuire/option 特性: 这个特性有两个作用,一是压缩,有时候一个协议很多字段,有些字段可以带上也可以不带上,不赋值的时候不是也要带一个缺省值打包,这样很浪费,如果字段是 option 特性,没有赋值的话,就不用打包。二是约束功能,规定哪些字段必须有,加强校验。

序列化是通信协议的基础,不管是信令通道还是数据通道,还是 rpc,都需要使用到。在设计协议早期就考虑到扩展性和跨语言特性。会为以后省去不少麻烦。

Ps

この部分は、バイナリ通信プロトコル、話さないテキストプロトコルのシーケンスを説明します。ある意味では、テキストプロトコルの互換性と拡張性を持って生まれ。バイナリとは異なり、非常に多くの問題を考慮する必要があります。デバッグプロトコルに簡単にテキストは習得が容易、(パケットキャプチャが見えるキャラクター、デバッグにtelnetがあるような、データ・パケットは、手動で特別なツールの助けを借りずに生成することができます)最も強力な利点です。バイナリプロトコルの利点は、パフォーマンスとセキュリティです。しかし、トラブルがデバッグ。

強みと弱み、需要の両方のオプション

参考:

転送この記事https://www.jianshu.com/p/fb183509f14d

https://www.jianshu.com/p/73c9ed3a4877
https://www.jianshu.com/p/72108f0aefca


毎日少しを記録する意向。おそらく、内容は重要ではありませんが、習慣は非常に重要です!

おすすめ

転載: www.cnblogs.com/binarylei/p/10991550.html