簡體   English   中英

在ANSI C中表示BER TLV數據結構?

[英]Representing BER TLV data structure in ANSI C?

昨天我開始了解使用TLV格式表示信息。

如果您要在ANSI C中編寫便攜式BER TLV編碼器/解碼器,您將使用哪種數據結構(*)?

會不會像下面那樣呢?

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

(*)不幸的是我不能使用C ++和STL。

來自維基文章:

類型和長度大小固定(通常為1-4個字節)

所以,我將nTagnLength更改為某個固定長度類型。 int的大小是特定於平台的,這可能會給你帶來一些麻煩。 修復協議的大小並使用int8_tint16_tint32_t等。對於nLength ,您甚至可以使用unsigned。


因為值可以是任何類型,我將使用void*作為pValue ,而不是unsigned char*


您將如何使用此數據結構? 您希望如何訪問不同的TLV?
我的觀點是 - 你需要鏈表嗎? 或者,鏈接列表是您的案例/應用程序/目的/等的最佳選擇嗎?

我想說的是,您可以刪除pNext元素並將TLV視為(動態增長的)數組的元素。 這個真的取決於你的需求。

最有可能的是,當你實現TLV時,你需要通過某種連接發送它們,對吧? 如果是這樣,你需要考慮一些協議。 我會做這樣的事情 - 在最開始發送TLV的總數,我不會使用鏈表,而是動態數組。
您應該小心通過網絡發送此類數據結構 - pNext指針無效,必須在連接的另一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

注意:再一次,這不是經過測試的代碼,但我想你明白了。 希望有所幫助。

如果我要用ANSI C編寫TLV編碼器/解碼器,我會選擇經過驗證,標准化,靈活的數據序列化 (即線上 )格式: ASN.1 BERThrift

這是一個經典的區域,輪子每天都會被重新發明。 聰明人已經想到了高效,可維護和靈活的解決方案; 再次經歷同樣的過程沒有什么意義。

例如,如果您的示例中的結構用於序列化 ,您仍需要考慮:

  • Endianess問題
  • 語言類型的大小( int的大小取決於編譯器平台和OS)
  • 有效負載中的數據類型(您可能希望攜帶原始數據,字符串,數字,位字段,枚舉等)
  • 標簽號的集中分配
  • 可選元素和選擇
  • 復合結構(例如TLV列表)

一些現有格式提供語義和語法之間的分離; 其他允許您自動生成數據方案的編碼器/解碼器。

一旦選擇了序列化格式,就可以開始考慮內存中的格式,這在很大程度上取決於應用程序如何操作數據,例如:

  • 應用程序如何在解碼后提取數據(例如,給定一個整數項,應用程序是否訪問編碼表示或可以輕松使用的本機表示?)
  • 應用程序在編碼之前如何准備數據
  • 應用程序是否是多線程的
  • 是否要最小化復制開銷(例如,如果您有大量原始數據,是否需要復制它以對其進行編碼?如果原始數據是碎片的,您是否需要在連續內存中的某處重新組合以對其進行編碼? )
  • 解碼和解碼是否可以遞增完成
  • 分配的內存如何屬於:應用程序或庫?
  • 如何處理缺少內存和未知標記等錯誤

我建議看看asn1c生成的用於處理ASN.1 BER的API,或者libtasn1的API。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM