Protocol Buffers
| 開発元 | |
|---|---|
| 初版 | 2008年7月7日 |
| 最新版 | 2.4.1 / 2011年4月30日 |
| プラットフォーム | クロスプラットフォーム |
| サポート状況 | Active |
| 種別 | シリアライズフォーマットおよびライブラリ, インタフェース記述言語コンパイラ |
| ライセンス | BSDライセンス |
| 公式サイト | developers.google.com/protocol-buffers/ |
Protocol Buffers(プロトコルバッファー)はインタフェース定義言語(IDL)で構造を定義する通信や永続化での利用を目的としたシリアライズフォーマットであり、Googleにより開発されている。オリジナルのGoogle実装はC++、Java、Pythonによるものであり、フリーソフトウェアとしてオープンソースライセンスで公開されている。また、ActionScript・C言語・C#・Clojure・Common Lisp・D言語・Erlang・Go・Haskell・JavaScript・Lua・MATLAB・Mercury・Objective-C・OCaml・Perl・PHP・R言語・Ruby・Scala・.NET Frameworkなどの実装が利用可能である[1]。
目次 |
概要[編集]
Protocol Buffersのデザインの目的はシンプルさとパフォーマンスである。とりわけ、XMLより高速になるようデザインされている。Google は XML との比較で、3〜10倍小さく、20〜100倍高速であると主張している[2]。Google が挙げている例では、XML では 69 バイト以上の物が Protocol Buffers では 28 バイトであり、パースに 5〜10 マイクロ秒かかるのが、0.1〜0.2 マイクロ秒ですむとしている。
Protocol BuffersはGoogleではデータの保存や構造化されたあらゆる種類の情報の交換で用いられている。Protocol Buffers サーバーはカスタマイズされた RPC に基づいており、Googleにおける全てのマシン間通信で実際に用いられている。[3]
Protocol Buffersは既にあるサービス向けへの明確なRPCスタックを含まない部分を除いてFacebookによるThriftプロトコルに非常に似ている。Protocol Buffersはオープンソースであり、RPCスタックはこれらのギャップを埋めるために生まれてきた。[要出典]
データ構造およびサービスはプロトコル定義ファイル(Proto Definition file (.proto))でデザインされ、protocプログラムによりコンパイルされる。このコンパイル作業により目的のサービスに適合するコードが生成される。例として、「example.proto」は「example.pb.cc」および「example.pb.h」を生成し、この中には「example.proto」で定義されたメッセージおよびサービスのためのC++クラスが定義されている。
Protocol Buffersによりあらゆる種類のフォーマットをシリアライズすることができるようになる。公式にサポートされた実装では完全なリフレクションインターフェイスが利用可能であり、XMLやJSONと同じくらい容易にシリアライズ機構を整備することができる。
Protocol Buffersの主な目的としてはネットワークの通信を円滑にすることではあるが、そのシンプルさおよび高速さによりC++クラスおよび構造体を用いたデータ保持からの有力な置き換えとなっている。
例[編集]
以下のように、polyline.proto ファイルを作成する。
option java_package = "com.example"; option java_outer_classname = "PolyLineProtos"; // 点 message Point { required int32 x = 1; required int32 y = 2; optional string label = 3; } // 線分 message Line { required Point start = 1; required Point end = 2; optional string label = 3; } // 多角形 message PolyLine { repeated Point point = 1; optional string label = 2; }
Point メッセージは2つの必須フィールド x と y を定義している。label フィールドはオプションである。それぞれのフィールドはタグ番号を持っている。このタグ番号はイコール記号「=」の後で定義される。(例: xはタグ番号 1 を持つ)。タグ番号は1以上の自然数であり、タグ番号でフィールドを識別するため、重複なく必ず指定しないといけない。
Line および Polyline メッセージは Protocol Buffers による入れ子メッセージの例であり、どちらも Point を用いている。PolyLine は繰り返しフィールド point を持ち、ベクトルとして扱う。
メッセージのフィールドには required, optional, repeated のどれかが指定可能。また、値の型としては、各種プリミティブ型の整数や浮動小数点数、bool、string、bytes を指定可能。optional はデフォルト値を指定可能。repeated は Java では java.util.List になる。
この後、これを protoc によりコンパイルし、PolyLineProtos.java や polyline.pb.h などが生成される。
Java の場合は、以下のように利用することができる。
import com.example.PolyLineProtos.Point; import com.example.PolyLineProtos.Line; import com.example.PolyLineProtos.PolyLine; Point start = Point.newBuilder().setX(10).setY(20).build(); Point end = Point.newBuilder().setX(30).setY(40).build(); Line line1 = Line.newBuilder().setStart(start).setEnd(end).setLabel("LINE1").build(); byte[] bytes = line1.toByteArray(); Line line2 = Line.parseFrom(bytes); PolyLine.Builder polyLineBuilder = PolyLine.newBuilder(); for (int i = 0; i < 5; i++) { polyLineBuilder.addPoint(Point.newBuilder().setX(i).setY(i)); } PolyLine polyLine = polyLineBuilder.build();
C++ の場合は、以下のように利用することができる。
#include "polyline.pb.h" // 'protoc polyline.proto'のコマンドラインからの呼び出しにより自動生成される Line* createNewLine(const std::string& name) { Line* line = new Line; line->mutable_start()->set_x(10); line->mutable_start()->set_y(20); line->mutable_end()->set_x(30); line->mutable_end()->set_y(40); line->set_label(name); return line; } PolyLine* createNewPolyline() { PolyLine* polyline = new PolyLine; Point* point1 = polyline->add_point(); point1->set_x(10); point1->set_y(10); Point* point2 = polyline->add_point(); point2->set_x(10); point2->set_y(10); return polyline; }
エンコーディング[編集]
各フィールドごとに順番にエンコードされるが、各フィールドの先頭にはタグ番号と3ビットで表現された型の種類がつく。
int32 などの整数値をエンコードした場合、必ず4バイト使うというわけではなく、0に近い数字はより少ないバイト数で表現される可変長数値表現を利用している。7ビット以下で表現できる整数は1バイトでエンコードされる。int32 も int64 もエンコード結果は同じ値になる。タグ番号+3ビット型種別も同じく可変長数値表現でエンコードされる。ただし、fixed32, fixed64 などを使うと固定長でエンコードされる。また、float, double などの浮動小数点数も固定長でエンコードされる。
文字列やバイト配列は、先頭に長さがつく形でエンコードされる。長さは上記の可変長数値表現を使っているため、長さの32ビット制限などはない。文字列は UTF-8 で符号化する。
可変長数値表現は数値をリトルエンディアンで表現し7ビット単位で区切り、それぞれの最上位ビットにフラグを立てて8ビット単位のバイト列に変換する。最上位ビットは最終バイトだけ0として、それ以外は1を立てる。符号付き整数の場合はジグザグエンコーディングを使い、32ビットの場合は (n << 1) ^ (n >> 31) で正の数に変換してから可変長数値表現を使う。両方を併用した場合、-64〜63が1バイト、-8192〜8191が2バイトになり、32ビット整数は最長5バイトで表現される。
関連項目[編集]
参照[編集]
- ^ Third-Party Add-ons for Protocol Buffers
- ^ Developer Guide - Protocol Buffers — Google Developers
- ^ Kenton Varda. “Steve Vinoskiへの返事(英語)”. 2008年7月14日閲覧。