5

バイナリ データをデバイスとの間でパケット (64 バイト) で送受信しています。データには特定の形式があり、その一部は要求/応答によって異なります。

現在、受信したデータのインタープリターを設計しています。位置ごとにデータを読み取るだけでも問題ありませんが、さまざまな応答形式がある場合はそれほどクールには見えません。私は現在、その目的のためにいくつかの構造体を作成することを考えていますが、パディングがどうなるかわかりません。

多分もっと良い方法がありますか?


関連している:

4

5 に答える 5

8

構造体または共用体を使用する必要があります。接続の両側でデータが適切にパックされていることを確認する必要があります。また、接続のどちらかの側が異なるバイト オーダーで実行されている可能性がある場合は、両端でネットワーク バイト オーダーとの間で変換することをお勧めします。エンディアン。

例として:

#pragma pack(push)  /* push current alignment to stack */
#pragma pack(1)     /* set alignment to 1 byte boundary */
typedef struct {
    unsigned int    packetID;  // identifies packet in one direction
    unsigned int    data_length;
    char            receipt_flag;  // indicates to ack packet or keep sending packet till acked
    char            data[]; // this is typically ascii string data w/ \n terminated fields but could also be binary
} tPacketBuffer ;
#pragma pack(pop)   /* restore original alignment from stack */

そして、割り当てるとき:

packetBuffer.packetID = htonl(123456);

そして、受け取ったとき:

packetBuffer.packetID = ntohl(packetBuffer.packetID);

ここでは、エンディアンアライメント、および構造体のパッキングについて説明します。

構造体をパックしないと、単語の境界に合わせて配置され、構造体の内部レイアウトとサイズが正しくなくなります。

于 2009-05-12T12:04:23.143 に答える
3

私はこれまでに数え切れないほどこれを行ってきました。これは非常に一般的なシナリオです。私が事実上常に行っていることがいくつかあります。

利用可能な最も効率的なものにすることについてあまり心配しないでください。

パケットのパックとアンパックに多くの時間を費やすことになった場合は、いつでもより効率的に変更できます。まだ必要なケースに遭遇したことはありませんが、ネットワークルーターを実装していません!

構造体/共用体を使用することはランタイムの点で最も効率的なアプローチですが、いくつかの複雑な問題が伴います: 必要なパケットのオクテット構造に一致するように構造体/共用体をパックするようにコンパイラーを説得し、アラインメントとエンディアンの問題を回避するように働きかけます。 、およびデバッグビルドでサニティチェックを行う機会がまったくないかほとんどないため、安全性の欠如.

私はよく、次のようなものを含むアーキテクチャにたどり着きます。

  • パケット基本クラス。すべての共通データ フィールドにアクセスできます (ただし、変更はできません)。データがパック形式で保存されていない場合は、パックされたパケットを生成する仮想関数があります。
  • 共通のパケット タイプから派生した、特定のパケット タイプ用の多数のプレゼンテーション クラス。パッキング関数を使用している場合、各プレゼンテーション クラスはそれを実装する必要があります。
  • プレゼンテーション クラスの特定のタイプ (つまり、共通データ フィールドからのパケット タイプ ID) から推測できるものはすべて、初期化の一部として処理され、それ以外の場合は変更できません。
  • 各プレゼンテーション クラスは、アンパックされたパケットから構築できます。または、パケット データがそのタイプに対して無効である場合は正常に失敗します。これは、利便性のために工場で包装することができます。
  • 利用可能な RTTI がない場合は、パケット ID を使用して「貧乏人の RTTI」を取得し、オブジェクトが実際にどの特定のプレゼンテーション クラスであるかを判断できます。

これらすべてにおいて、変更可能な各フィールドが適切な値に設定されていることを (デバッグ ビルドの場合でも) 確認することができます。大変な作業のように思えるかもしれませんが、無効なフォーマットのパケットを作成することは非常に困難です。事前にパックされたパケットの内容は、デバッガーを使用して目で簡単に確認できます (すべて通常のプラットフォーム固有のフォーマット変数であるため)。

より効率的なストレージ スキームを実装する必要がある場合でも、パフォーマンス コストをほとんど追加せずに、この抽象化にラップすることができます。

于 2009-05-12T20:22:20.033 に答える
3

データの正確な形式を知らずに、何が最善の解決策であるかを言うのは困難です。ユニオンの使用を検討しましたか?

于 2009-05-12T12:03:44.470 に答える
1

これは「すぐに使える」ソリューションですが、Pythonコンストラクトライブラリを参照することをお勧めします。

Construct は、データ構造 (バイナリまたはテキスト) の解析と構築のための Python ライブラリです。これは、手続き型のコードではなく、宣言的な方法でデータ構造を定義するという概念に基づいています。より複雑な構造は、より単純なものの階層で構成されています。今日の通常の頭痛の代わりに、解析を楽しくする最初のライブラリです。

構成は非常に堅牢で強力であり、チュートリアルを読むだけで問題をよりよく理解するのに役立ちます. 作成者は、定義から C コードを自動生成する計画も持っているので、一読する価値は間違いなくあります。

于 2009-05-15T12:30:59.757 に答える
1

ウギーさんに同意。コード生成を使用してこれを行うこともできます。シンプルなデータ定義ファイルを使用してすべてのパケット タイプを定義し、それに対して Python スクリプトを実行して、それぞれのプロトタイプ構造とシリアル化/非シリアル化関数を生成します。

于 2009-05-12T23:30:52.987 に答える