2

実際の制御システム デバイスの 1 つと通信する C アプリケーションを開発しています。デバイスは、明確に定義されたプロトコル構造を使用します。たとえば、要求されたときにデバイスが UDP パケットとして送信する構造の 1 つを考えてみましょう。

typedef struct poll_request_s {
   uint16             poll_number; /* poll number mirrored from the 
                                    * poll request */
   uint16             length;      /* length of the message */

   /* till above it was all header section this is ACTUAL DATA */
   attribute_list_t   attr_list;   /* this attribute list contains 
                                    * various attributes */
} poll_request_t

現在、さまざまな属性をパックする構造体であり、このリスト内の各属性は(16 ビット整数)attribute_list_tの識別子番号によって識別されます。uint16つまり、プロトコルは次のように機能します。

  • いくつかのデータを要求します。
  • 属性リストの形式でデータを取得します。
  • 属性リストの各属性には、オブジェクト識別子があります。
  • このオブジェクト識別子を使用して、各属性を解析 (ホストのバイト順に変換) します。
  • 属性自体にさらに属性リストが含まれる場合があります。(属性開始)

このatrtribute_list_t構造は以下のようなものです:-

typdef struct attribute_list_s {
   uint16  length;       /* length of attribute list */
   uint16  count;        /* number of attributes in this list */
   uint8   attrs_data[]; /* another container to hold attributes' data */
} attribute_list_t

attrs_dataは、リスト内のすべての属性を保持するための単なるプレース ホルダーです。実際、これは、属性情報を読み取るためにattrs_data呼び出される別の構造体にキャストする必要があります。ava_type

typdef struct ava_type_s {
   uint16 attr_id; /* type of attribute */
   uint16 length;  /* length of this attribute 
                    *(this length of single attribute not whole list*/
   uint8  data[];  /* another flexible array to hold data for this 
                    * attribute type */
}

さて、この構造内の属性を反復して解析するために、現在このアルゴリズムを使用しています (以下の疑似コード):

uint8* packet = recv_packet(SOCKET);
/* this is used as packet iterator pointer */
unit8* packet_ptr = packet;
parsed_packet_t parsed_packet = malloc(SOME_SIZE);
.
. /* do header un-packing */
.
/* dont need attribute_list length so skip this 2 bytes */
parsed_packet += 2;

/* parsed packet do nee count of attributes */
parsed_packet.attribute_list->count = NTOHS(packet_ptr);
packed_ptr += 2; /* skip count */

/* now packet_ptr is pointer to attr_list */
offset = 0, i = 0;
for(i = 0 to attr_list->count) {
   /* cast the attributes' data to ava_type */
   packet_ptr += offset;

   /* parse object identifier */
   parsed_packet.attribute_list->data[i++].object_id = NTOHS(packet_ptr);
   packet_ptr += 2; /* skip 2 bytes */

   /* next offset would be attribute length of this packet */
   attribute_length += 2 + NTOHS(packet_ptr);
   packet_ptr += 2;

   /* now we are pointer to actual data of i(th) attribute */

   /* I've made this parser structure and hash table to
    * retrieve the parser for particular attr_id */
   parser* p = HASH_TABLE(ava_type->attr_id);

   /* parser has function point for network order to host 
    * order and visa-versa */
   p->ntoh(ava_type, parsed_packet.attribute_list->data[i]);
}

さて、私の質問は次のとおりです。

  • それでも、HASH_TABLE上記のアルゴリズムでアプローチを示しましたが、実際には 20 から 30 を使用していIF-ELSEます。hash tableC にはinがないためstdlib。プロトコルには約 600 の構造体があり、600 を書きたくありませんif-else。に従ってこれらの構造を解析することについて、どのような提案と方法を提供しますかattribute_id
  • もう 1 つの問題は、私が定義した構造体でのコンパイラのパディングです。私のすべての構造はflexible array、データコンテナのフィールドで定義されています。現在、メッセージを受信すると、lengthほとんどすべての属性が含まれていますが、コンパイラが魔法のようにいくつかのパディングバイトを追加し、バイトが不足する可能性があるため、これは解析された構造にはlength使用できません。malloc..ing私は通常、安全のためにmalloc..ing約バイトです。lenght + 300実際、これはメモリ管理のやり方が悪いように思えます。この問題に関する提案はありますか?

malloc..ing受信したメッセージを解析するための構造は、これまでのところ私にとって最大の問題です。私はそれを行うためのメモリ効率的で高速な方法が欲しいですか?

また、そのようなプロジェクトをすでに行っている場合は、そのアプローチを教えていただけますか? 私を正しい方向に導くための提案やコメントはありますか? 必要以上に複雑にせず、シンプルなデザインが欲しい。

4

1 に答える 1