実際の制御システム デバイスの 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 table
C にはinがないためstdlib
。プロトコルには約 600 の構造体があり、600 を書きたくありませんif-else
。に従ってこれらの構造を解析することについて、どのような提案と方法を提供しますかattribute_id
。 - もう 1 つの問題は、私が定義した構造体でのコンパイラのパディングです。私のすべての構造は
flexible array
、データコンテナのフィールドで定義されています。現在、メッセージを受信すると、length
ほとんどすべての属性が含まれていますが、コンパイラが魔法のようにいくつかのパディングバイトを追加し、バイトが不足する可能性があるため、これは解析された構造にはlength
使用できません。malloc..ing
私は通常、安全のためにmalloc..ing
約バイトです。lenght + 300
実際、これはメモリ管理のやり方が悪いように思えます。この問題に関する提案はありますか?
malloc..ing
受信したメッセージを解析するための構造は、これまでのところ私にとって最大の問題です。私はそれを行うためのメモリ効率的で高速な方法が欲しいですか?
また、そのようなプロジェクトをすでに行っている場合は、そのアプローチを教えていただけますか? 私を正しい方向に導くための提案やコメントはありますか? 必要以上に複雑にせず、シンプルなデザインが欲しい。