4

昨日、 TLV形式で情報を表現することを知りました。

ポータブルBERTLVエンコーダー/デコーダーをANSICで作成する場合、どのデータ構造を使用しますか(*)?

次のようなことはしますか?

struct TlvElement
{
    int nTag;
    int nLength;
    unsigned char *pValue; // Byte array
    TlvElement *pNext;
}; 

(*)残念ながら、これにはC++とSTLを使用できません。

4

2 に答える 2

3

wikiの記事から:

タイプと長さはサイズが固定されています(通常は1〜4バイト)

そこで、nTagnLengthを固定長タイプに変更します。intのサイズはプラットフォーム固有であり、これにより問題が発生する可能性があります。プロトコルに合わせてサイズを修正し、、、などを使用しますint8_tint16_tint32_t場合nLengthは、unsignedを使用することもできます。


値は任意のタイプである可能性があるvoid*ためpValue、の代わりにを使用しunsigned char*ます。


このデータ構造をどのように使用しますか?さまざまなTLVにどのようにアクセスしたいですか?
私のポイントは-リンクリストが必要ですか?または、リンクリストはあなたのケース/アプリケーション/目的などに最適なオプションですか?

私が言おうとしているのは、pNext要素を削除して、TLVを(動的に成長する)配列の要素として扱うことができるということです。これは本当にあなたのニーズに依存します。

おそらく、TLVを実装しているときに、何らかの接続を介してTLVを送信する必要がありますよね?もしそうなら、あなたはいくつかのプロトコルについて考える必要があります。私はこのようなことをします-最初にTLVの総数を送信し、リンクリストではなく動的配列を使用します。
このようなデータ構造をネットワーク経由で送信する場合は注意が必要pNextです。ポインタは有効ではないため、接続の反対側でリセットする必要があります。
また、慎重にデータを送信する必要がありますが、私はあなたがこれらのことを知っていると思います。私はそれらについて言及したかっただけです。


編集ネストされたTLVの意味を理解するのに問題があるようです。

ネストされたTLVは、TLVタイプの値を持つ単なるTLV要素です。そして、これはTLVの「コンテナ」(動的配列またはリンクリスト)とは何の関係もありません。

これは、アイデアを得るために、テストされていない例です私はこれをこのようにします:

struct TLV
{
    uint32_t nTag;
    uint32_t nLength;
    void* pValue;
};

// created dynamic array with 3 TLVs:
TLV* pMyTLVs = malloc( 3 * sizeof( struct TLV ) );

// set the first 2 TLVs, some primitives, for example
// ..

// now, set the third TLV to be nested:
pMyTLVs[ 2 ].nTag = ...; // set some tag, that will indicate nested TLV
pMyTLVs[ 2 ].nLength = ...; // set length of the TLV element
pMyTLVs[ 2 ].pValue = malloc( sizeof( struct TLV ) );

// get pointer to the new, _nested_ TLV:
TLV* pNested = (TLV*)pMyTLVs[ 2 ].pValue; 

// now use the pNested TLV as an usual TLV:
pNested->nTag = ...;
pNested->nLength = ...;
pNested->pValue = ...;

// of course, pNested is not absolutely necessary, you may use directly
// pMyTLVs[ 2 ].pValue->...;
// but using pNested, makes the code more clear

注:繰り返しになりますが、これはテスト済みのコードではありませんが、あなたはその考えを理解していると思います。お役に立てば幸いです。

于 2012-08-11T08:55:46.433 に答える
1

TLVエンコーダー/デコーダーをANSICで作成する場合は、実績のある、標準化された、柔軟なデータシリアル化(つまり、オンワイヤー)形式を選択します:ASN.1 BERThriftなど。

これは、ホイールが日常的に再発明される古典的なエリアです。賢明な人々は、効率的で、保守可能で、柔軟性のあるソリューションをすでに考えています。同じプロセスをもう一度実行しても意味がありません。

たとえば、例の構造がシリアル化に使用された場合でも、次のことを考慮する必要があります。

  • エンディアンの問題
  • 言語タイプのサイズ(サイズはintコンパイラプラットフォームとOSによって異なります)
  • ペイロード内のデータのタイプ(生データ、文字列、数値、ビットフィールド、列挙などを伝送したい場合があります)
  • タグ番号の一元化された割り当て
  • オプションの要素と選択肢
  • 複合構造(TLVのリストなど)

一部の既存の形式は、セマンティクスと構文を分離します。その他の方法では、データスキーマのエンコーダー/デコーダーを自動的に生成できます。

シリアル化形式を選択したら、メモリ内形式の検討を開始できます。これは、アプリケーションがデータを操作する方法に大きく依存します。たとえば、次のようになります。

  • アプリケーションは、デコード後にデータをどのように抽出しますか(たとえば、整数項目が与えられた場合、アプリケーションは、エンコードされた表現またはすぐに使用できるネイティブ表現にアクセスしますか?)
  • アプリケーションがエンコードする前にデータを準備する方法
  • アプリケーションがマルチスレッドかどうか
  • コピーのオーバーヘッドを最小限に抑えたいかどうか(たとえば、大量の生データがある場合、それをエンコードするために複製する必要がありますか?生データが断片化されている場合、それをエンコードするために連続したメモリのどこかに再構成する必要がありますか? )。
  • デコードとデコードを段階的に実行できるかどうか
  • 割り当てられたメモリはどのように属しますか:アプリケーションまたはライブラリ?
  • メモリ不足や不明なタグなどのエラーの処理方法

ASN.1 BERを処理するためにasn1cによって生成されたAPI、またはlibtasn1のAPIを確認することをお勧めします

于 2012-08-11T09:44:29.007 に答える