序文
以前は、ネットワーク通信や一般的なデータ交換などのアプリケーションシナリオでよく使用されるテクノロジーは、JSONまたはXMLでしたが、最近の開発では、GoogleのProtoBufに連絡がありました。
関連資料を参考にしてProtoBufを学び、そのソースコードを調べたところ、効率と互換性の点で非常に優れていることがわかりました。将来のプロジェクト技術の選択では、特にネットワーク通信や一般的なデータ交換などのシナリオでは、ProtoBufを優先する必要があります。
ProtoBufを学ぶ過程で、公式の主要文書を翻訳しました。まず、もちろんProtoBufを学びます。次に、英語の文書を読む能力を養います。第三に、それはGoogleの文書によるものですか。存在しない!
これらのドキュメントを読んだ後は、ProtoBufについてかなり理解しているはずです。
翻訳ドキュメントについては、[Index]記事のインデックスを参照し、Translation-Technology-ProtoBuf OfficialDocumentsに移動してください。
ただし、公式文書は検査と信頼できる参照のためのものであり、公式文書を読んだ後すぐに原則を理解できるという意味ではありません。
この記事と次のいくつかの記事では、ProtoBufのエンコード、シリアル化、逆シリアル化、およびリフレクションの原則を詳細に紹介し、これらの原則をより簡単かつ理解しやすく表現しようとします。
ProtoBufとは
まず、公式文書に記載されている定義と説明を見てみましょう。
プロトコルバッファは、構造化データをシリアル化するための言語やプラットフォームに依存しない拡張可能な方法であり、(データ)通信プロトコルやデータストレージなどに使用できます。
Protocol Buffersは、柔軟で効率的で自動化された構造化データのシリアル化方法です。XMLに匹敵しますが、XMLよりも小さく(3〜10倍)、高速で(20〜100倍)、単純です。
データの構造を定義してから、特別に生成されたソースコードを使用して、さまざまな言語のさまざまなデータストリームで構造化データを簡単に読み書きできます。古いデータ構造からコンパイルされたデプロイ済みプログラムを破棄せずに、データ構造を更新することもできます。
簡単に言うと、ProtoBufは構造化されたデータシリアル化[1]メソッドであり、XML [2]に簡単に類推できます。次の特徴があります。
- 言語はプラットフォームとは何の関係もありません。つまり、ProtoBufはJava、C ++、Python、およびその他の言語をサポートし、複数のプラットフォームをサポートします
- 効率的。これは、XMLよりも小さく(3〜10倍)、高速(20〜100倍)で、単純です。
- 優れたスケーラビリティと互換性。元の古いプログラムに影響を与えたり破壊したりすることなく、データ構造を更新できます
シリアル化[1]:構造化データまたはオブジェクトを保存および送信可能な形式(ネットワーク送信など)に変換すると同時に、シリアル化された結果を後で元に再構築できるようにする必要があります(場合によっては)別のコンピューティング環境で)データまたはオブジェクトの構造。
より詳細な説明はウィキペディアにあります。
XML [2]へのアナロジー:これは主にデータ通信およびデータストレージアプリケーションシナリオでのシリアル化のアナロジーを指しますが、拡張マークアップ言語としてのXMLは本質的にProtoBufとは異なると私は個人的に思います。
ProtoBufを使用する
ProtoBufの基本的な概念をある程度理解した後、ProtoBufの使用方法を見てみましょう。
最初のステップは、以下の例1に示すように、.protoファイルを作成し、データ構造を定義することです。
// 例1: 在 xxx.proto 文件中定义 Example1 message
message Example1 {
optional string stringVal = 1;
optional bytes bytesVal = 2;
message EmbeddedMessage {
int32 int32Val = 1;
string stringVal = 2;
}
optional EmbeddedMessage embeddedExample1 = 3;
repeated int32 repeatedInt32Val = 4;
repeated string repeatedStringVal = 5;
}
上記の例では、Example1という名前のメッセージを定義しました。構文は非常に単純です。messageキーワードの後にメッセージ名が続きます。
message xxx {
}
その後、メッセージのフィールドを次の形式で定義しました。
message xxx {
// 字段规则:required -> 字段只能也必须出现 1 次
// 字段规则:optional -> 字段可出现 0 次或1次
// 字段规则:repeated -> 字段可出现任意多次(包括 0)
// 类型:int32、int64、sint32、sint64、string、32-bit ....
// 字段编号:0 ~ 536870911(除去 19000 到 19999 之间的数字)
字段规则 类型 名称 = 字段编号;
}
上記の例では、次のように定義しました。
- string、stringValという名前のオプションのフィールドを入力します。フィールド番号は1で、このフィールドは0回または1回表示されます。
- バイトを入力します。bytesValという名前のオプションのフィールドです。フィールド番号は2です。このフィールドは、0回または1回表示できます。
- タイプEmbeddedMessage(カスタム埋め込みメッセージタイプ)、embeddedExample1という名前のオプションフィールド、フィールド番号は3、このフィールドは0回または1回表示できます
- int32と入力します。repatedInt32Valという名前の繰り返しフィールドです。フィールド番号は4です。このフィールドは、何度でも表示できます(0を含む)。
- 文字列を入力し、repeatedStringValという名前の繰り返しフィールド、フィールド番号は5、このフィールドは何度でも表示できます(0を含む)
サポートされているタイプ、フィールド番号の割り当て、インポート
定義、予約済みフィールドなど、メッセージメッセージのproto2定義の文法的な詳細については、[翻訳] ProtoBuf公式ドキュメント(2)-構文ガイドライン(proto2)を参照してください。。
一部の仕様の定義については、[翻訳] ProtoBuf公式ドキュメント(4)-仕様ガイドラインを参照してください。
2番目のステップであるprotocは、.protoファイルをコンパイルして読み取り/書き込みインターフェイスを生成します
.protoファイルでデータ構造を定義します。これらのデータ構造は、開発者およびビジネスプログラム向けであり、保存および送信用ではありません。
これらのデータを保存または送信する必要がある場合、これらの構造化データをシリアル化、逆シリアル化、および読み取りと書き込みを行う必要があります。では、どのようにそれを達成するのですか?心配しないでください。ProtoBufは対応するインターフェースコードを提供してくれます。提供する方法は?答えは、protocコンパイラを使用することです。
対応するインターフェイスコードは、次のコマンドで生成できます。
// $SRC_DIR: .proto 所在的源目录
// --cpp_out: 生成 c++ 代码
// $DST_DIR: 生成代码的目标目录
// xxx.proto: 要针对哪个 proto 文件生成接口代码
protoc -I=$SRC_DIR --cpp_out=$DST_DIR $SRC_DIR/xxx.proto
最終的に生成されたコードは、次のようなインターフェイスを提供します。
例-シリアル化と解析interface.png
例-プロトコル生成interface.png
3番目のステップは、インターフェースを呼び出して、シリアル化、逆シリアル化、および読み取りと書き込みを実行すること
です。最初のステップで例1で定義したメッセージの場合、2番目のステップで生成されたインターフェースを呼び出して、次のようにテストコードを実装できます。
//
// Created by yue on 18-7-21.
//
#include <iostream>
#include <fstream>
#include <string>
#include "single_length_delimited_all.pb.h"
int main() {
Example1 example1;
example1.set_stringval("hello,world");
example1.set_bytesval("are you ok?");
Example1_EmbeddedMessage *embeddedExample2 = new Example1_EmbeddedMessage();
embeddedExample2->set_int32val(1);
embeddedExample2->set_stringval("embeddedInfo");
example1.set_allocated_embeddedexample1(embeddedExample2);
example1.add_repeatedint32val(2);
example1.add_repeatedint32val(3);
example1.add_repeatedstringval("repeated1");
example1.add_repeatedstringval("repeated2");
std::string filename = "single_length_delimited_all_example1_val_result";
std::fstream output(filename, std::ios::out | std::ios::trunc | std::ios::binary);
if (!example1.SerializeToOstream(&output)) {
std::cerr << "Failed to write example1." << std::endl;
exit(-1);
}
return 0;
}
protocおよびinterface呼び出しの使用の詳細については、[翻訳] ProtoBuf公式ドキュメント(9)-(C ++開発)チュートリアルを参照してください。
例1に示されている完全なコードについては、出典:protobuf例1を参照してください。その中で、single_length_delimited_all。*は、例の関連するコードとファイルです。
このシリーズの記事の焦点は、ProtoBufのコーディング、シリアル化、リフレクションなどの原則を深く掘り下げることであるため、ProtoBufの構文と使用法の簡単な紹介のみを示します。より詳細な使用法のチュートリアルについては、を参照してください。私が翻訳した一連の公式文書。
ProtoBufに関するいくつかの考え
インターネット上の公式文書や多くの記事では、ProtoBufはXMLまたはJSONに類似している可能性があると述べています。
では、ProtoBufはXMLやJSONと同等であり、それらはまったく同じアプリケーションシナリオを持っていますか?
個人的には、ProtoBuf、XML、JSONを一緒に比較したい場合は、2つの次元を区別する必要があると思います。1つはデータ構造化で、もう1つはデータのシリアル化です。ここでのデータ構造化は主に開発レベルまたはビジネスレベル向けであり、データシリアル化は通信レベルまたはストレージレベル向けです。もちろん、データシリアル化には「構造」と「フォーマット」も必要であるため、両者の違いは主にフィールド指向のさまざまなシナリオ。、一般的な要件と焦点は異なります。データの構造化は人間の可読性、場合によっては意味表現機能に焦点を当てていますが、データのシリアル化は効率と圧縮に焦点を当てています。
これらの2つの側面から、次のように考えることができます。
拡張マークアップ言語としてのXML、およびJSから派生したデータ形式としてのJSONには、データを構造化する機能があります。
たとえば、XMLはHTMLから派生させることができます(HTMLはXMLよりも前ですが、概念的には、HTMLは事前定義されたタグを持つ単なるXMLです)。HTMLの機能は、ワールドワイドウェブのリソースの構造をマークして表現することです。ブラウザはワールドワイドウェブリソースをより適切に表示できます。同時に、開発者が編集できるように可能な限り人間が読めるようにする必要もあります。これは、ビジネスまたは開発レベルのデータ構造です。
別の例として、XMLはRDF / RDFSを導出して、セマンティックWeb内のリソースの関係とセマンティクスをさらに表現することもできます。また、データ構造と人間が読める形式の機能を強調します。
RDF / RDFSとセマンティックWebの概念については、関連資料を参照するか、2-回答シリーズ-オントロジー構築モジュール(1)および3-回答シリーズ-オントロジー構築モジュール(2)を参照してください。簡単な紹介がいくつかあります。記事で。
JSONは同じです。多くの場合、インタラクティブなインターフェイスとしてのデータ構造の表現など、データ構造の機能を反映しています。MongoDBでクエリステートメントとしてJSONを使用することも、データを構造化する機能を発揮します。
もちろん、JSONとXMLはデータのシリアル化に直接使用することもできます。実際、これらは多くの場合にも使用されます。たとえば、JSONとXMLはネットワークの通信と送信に直接使用されます。このとき、JSONとXMLは一種のシリアル化。フォーマット、それはデータシリアル化の能力を発揮します。しかし、頻繁に使用されることは、そうすることが合理的であることを意味しません。実際、JSONとXMLは、速度、効率、スペースの点で最適ではないため、通常、データを直接シリアル化するのに最適な選択肢ではありません。つまり、データのシリアル化よりもデータの構造化に適しています。
XMLとJSONについて説明した後、ProtoBufを見てみましょう。同じProtoBufには、実際には上記のメッセージ定義であるデータを構造化する機能もあります。メッセージ、インポート、埋め込みメッセージなどの文法を使用して.protoファイルでデータ構造化を実現できますが、ProtoBufはデータ構造化の点でXMLやJSONとはかなり異なり、人間が読める形式であることが簡単にわかります。上記のXMLおよびJSONの一部のアプリケーションシナリオには適していません。
しかし、データのシリアル化の観点からは、ProtoBufには明らかな利点があり、効率、速度、およびスペースがほぼ完全に支配的であることがわかります。次のProtoBufコーディング記事を読むと、ProtoBufが可能な限りすべてのビットを圧縮する方法がわかります。 。1インチのスペースとパフォーマンス、そしてコーディングの原則がProtoBufの鍵であり、メッセージを表現する機能はProtoBufの最も重要な焦点ではありません。ProtoBufキーは、構造化されていないデータのデータシーケンスに焦点を当てていることがわかります。
最後に、これらの個人的な考えのいくつかの小さな要約を作成します。
- XML、JSON、およびProtoBufはすべて、データ構造化およびデータシリアル化機能を備えています
- XMLとJSONは、データ構造、人間の読みやすさ、意味表現能力にもっと注意を払っています。ProtoBufは、効率、スペース、速度、人間の可読性が低く、意味表現能力が不十分であることに焦点を当てて、データのシリアル化にさらに注意を払っています(究極の効率を確保するために、一部のメタ情報は破棄されます)
- ProtoBufのアプリケーションシナリオはより明確であり、XMLとJSONのアプリケーションシナリオはより豊富です。