8

現在のアプローチに満足できず、Erlang でプロトコル スタックを構築する方法を再設計しようとしています。重要度順に並べられた機能:

  1. パフォーマンス

  2. 新しいプロトコルバリアントを追加する柔軟性と実装速度

  3. 開発者がシェルからプロトコルのバリアントを探索するのに役立ちます

私の現在のモデル(すでにこの質問で説明されています)は、関数呼び出しによる send() とメッセージによる受信の醜い非対称性に加えて、限界に達しています。

プロトコル エンジン全体の全体像は次のようになります。

下部:

  • 各スタックの下部にいくつかのポートまたは場合によっては gen_tcp もあります (独立したチャネル用に複数の同一のスタックがあるため、ここでプロセスを登録するだけで静的になりすぎることはできず、どこにでも PID を渡す必要があります。

  • ポートの上には、スーパーバイザーによって管理されるいくつかのモジュールがあります (システムで開始され、エラーが発生しない限り、存続期間全体が維持されます)。

頭の部分:

  • (event_handler の意味ではなく一般的な意味で) イベントの発生によってトリガーされるのは、接続指向のプロトコルの終わりです (たとえば、connect()およびclose()セマンティクスを使用)。

  • スタックを形成するために互いの上に積み重ねられたモジュールは動的に構成可能であり、接続ごとに変更される可能性があるため、プロトコルスタックのトップエンドはおそらく動的にのみ開始できます。

  • 現在計画されているのは、モジュール名のリスト + オプションのパラメーターをトップレベルから渡すことでありconnect()、スタックに呼び出されている間に消費されます。

  • トップレベルのプロセスがリンクされるため、ここで何か問題が発生すると、接続全体が失敗します。

モジュールの種類とモジュール間の通信の種類

これまでに見つかったいくつかの種類のモジュールがあります。

  • ステートレス フィルター モジュール

  • 状態を持つモジュールは、一部は gen_server に適合し、一部は gen_fsm に適合しますが、ほとんどは単純なサーバー ループになるでしょう。

レイヤー間の通信の種類:

  • 独立したパケットの送受信(外から見て独立)

  • 何かを送信し、応答があるまでブロックし、結果を戻り値として返す同期呼び出し。

  • 複数のモジュールと通信するマルチプレクサ (議論を容易にするためにここで定義しています)

  • 上向きのモジュールと通信するための異なるアタッチメント ポイント (現在はアトムによって名前が付けられています) を持つデマルチプレクサ。

現在、私の唯一のデマルチプレクサはスタックの静的な下部にあり、動的に作成された上部にはありません。マルチプレクサは現在、上部のみにあります。

リンクされた以前の質問処理の回答とコメントで、一般的に API はメッセージではなく関数のみで構成されるべきであると聞きましたが、そうでないと確信しない限り、これに同意します。

問題の説明が長くなってしまい申し訳ありませんが、あらゆる種類のプロトコルの実装にまだ一般的に使用されていると思います。

ここで一般的に役立つ何かを達成するために、これまでに計画したことを回答に書き、結果として得られる実装とそれに関する私の経験についても説明します。

4

1 に答える 1

2

回答の一部として、これまでに計画したことを投入します。

  • connect はモジュールのリストをスタックに渡します。params の場合は proplist のようになります。

    connect([module1, module2, {module3, [params3]}], param0, further_params)
    

    各レイヤーは頭を取り除き、次のレイヤー接続を呼び出します。

  • connect()「どういうわけか」楽しい参照をレイヤーの上下に渡します

    • send for async スタックを下に送信すると、下位レベルの接続によって返されます
    • スタックを受信する非同期の recv は、param として下位レベルの接続に渡されます。
    • 同期送信の呼び出しと応答が返されるのを待っています -- これらを処理する方法がわかりません。おそらく下位レベルの接続からも返されます
  • マルチプレクサのルーティング リストは次のようになります。

    connect([module1, multiplexer, [[m_a_1, m_a_2, {m_a_3, [param_a_3]}], 
                                    [m_b_1, m_b_2],
                                    [{m_c_1, [param_c_1]}, m_c_2]], param0, 
                                                                    further_params]).
    

現在、同期呼び出し用の追加機能はないと判断しました。send を使用しているだけです。

この場合、ステートレスなモジュールのアイデアの実装例があります。パケットの for および back 変換を行います。たとえば、バイナリ表現をレコードに解析してから戻しますencode/1decode/1

connect(Chan, [Down|Rest], [], Recv_fun) ->
    {Down_module, Param} = case Down of
                               {F, P} -> {F, P};
                               F when is_atom (F) -> {F, []}
                           end,
    Send_fun = Down_module:connect(Chan, Rest, Param,
                                   fun(Packet) -> recv(Packet, Recv_fun) end),
    {ok, fun(Packet) -> send(Packet, Send_fun) end}.

send(Packet, Send_fun) ->
    Send_fun(encode(Packet)).

recv(Packet, Recv_fun) ->
    Recv_fun(decode(Packet)).

ステートフルな例ができたらすぐに投稿します。

于 2010-10-30T17:27:41.877 に答える