プログラムがErlangsサーバーにデータを転送する必要がある場合、このデータを最初にシリアル化する必要があります。 つまり、それらはバイナリ形式に変換されるため、アーランはそれらをアンパックできます。 これは通常、ASN.1、google protobuf、thriftなどを使用して行われます。 これらはすべて、間違いなく価値のある製品です。
または、Erlang外部用語形式の使用を検討してください。 Erlang実行可能システムには、2つの関数、
term_to_binary()および
binary_to_term()があります。これらの関数は、任意の値をこの形式にすばやく効率的にパック/アンパックできます。
erl_ext_dist.html
どのように機能しますか?
内線 その構造のフォーマットは非常に単純です。 通常、その中のデータの形式は「タグ、データ」または「タグ、長さ、データ」です。 タグは、どのタイプのデータがパックされるかを記述します。
基本的なデータ型の場合、タグは
- タプル-104 、要素数(1バイト)、すべての要素
- リスト -108、要素数(4バイト)、すべての要素、106
- アトム -115、長さ(1バイト)、アトムテキスト
- 整数 -98、値(4バイト)、または短整数 (255未満)-97、値(1バイト)
- 文字列 -107、長さ(2バイト)、テキスト。 原則として、文字列は整数のリストとしてエンコードできますが、8ビットテキストの短い文字列を転送する必要がある場合、このタグは医師が注文したものです
すべてのパックデータの前にタグ131を付ける必要があります。これは、現在のextのバージョン番号です。 用語の形式。
つまり、Erlang値[{banknote、100、rub}]は構造にパックされます:
概念実証として、たとえば、Pythonでext用語形式でpython構造をパックし、erlangで結果をアンパックする簡単な手順を記述します...
PythonリストをErlangリストに、PythonタプルをErlangタプルに、整数、Python行をパックします。 原子の場合...まあ...たとえば、Pythonの文字列から相続人を作成して、パッケージング手順で通常の文字列と簡単に区別できるようにします。
次のようになります:
from types import IntType, StringType, TupleType, ListType from struct import pack import socket class atom(str): pass def _eterm(x,accum): if type(x) is IntType: accum.append(pack('>Bi',98,x)) return if type(x) is StringType: accum.append(pack(">BH",107,len(x))) accum.append(x) return if type(x) is TupleType: accum.append(pack("BB",104,len(x))) for term in x: _eterm(term,accum) return if type(x) is ListType: accum.append(pack(">BI",108,len(x))) for term in x:_eterm(term,accum) accum.append(chr(106)) return if isinstance(x,atom): accum.append(pack("BB",115,len(x))) accum.append(x) return raise AssertionError("Cannot convert that type to erlang term %s"%(x)) def binary(X): accum = [chr(131)] _eterm(X,accum) return "".join(accum)
素晴らしい。 次に、ある種の複雑な構造をまとめて、最も簡単な方法でアーランに転送します。
pterm = (atom("vcard"),[(atom("firstname"),"Odobenus"), (atom("lastname"),"Rosmarus"), (atom("age"),48), (atom("children"),[ ("Dimon",1988), ("Natashka",1990), ("Katka",2000), ("Anka",2003)] ) erlterm = binary(pterm) sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) sock.sendto(erlterm,("localhost",10000))
つまり、彼らはudpパッケージをパックして送信しました。 Erlangでは、以下を受け入れて解読します。
1> gen_udp:open(10000,[binary]). {ok,#Port<0.585>} 2> R=receive {udp,_ ,_,_,Bin} -> Bin end. <<131,104,2,115,5,118,99,97,114,100,108,0,0,0,4,104,2,115, 9,102,105,114,115,116,110,97,109,101,107,...>> 3> binary_to_term( R ). {vcard,[{firstname,"Odobenus"}, {lastname,"Rosmarus"}, {age,48}, {children,[{"Dimon",1988}, {"Natashka",1990}, {"Katka",2000}, {"Anka",2003}]}]}
結論
私たちは(少し血で)pythonからアーランまで複雑な構造を渡しました。 このアプローチの利点は
- 柔軟性。 何でも梱包できます。
- パフォーマンス。 アーランでは、 binary_to_term()とterm_to_binary()は CでBIFとして実装され、速度とメモリについて最適化されています...
extの欠点。 用語形式:柔軟性には裏返しがあります。 曲がった手や愚かなプログラミングの場合、Erlangサーバーが何をすべきかを知らないだけの構造を詰めることができます。
記事の外では、倍精度数、無次元整数、圧縮データの転送、この形式へのバイナリのパッケージ化などの形式が残っていました。 など しかし、これらはすべてドキュメントに詳しく説明されています。
主なことは、アイデアを理解することです。