バイナリ データをデバイスとの間でパケット (64 バイト) で送受信しています。データには特定の形式があり、その一部は要求/応答によって異なります。
現在、受信したデータのインタープリターを設計しています。位置ごとにデータを読み取るだけでも問題ありませんが、さまざまな応答形式がある場合はそれほどクールには見えません。私は現在、その目的のためにいくつかの構造体を作成することを考えていますが、パディングがどうなるかわかりません。
多分もっと良い方法がありますか?
関連している:
バイナリ データをデバイスとの間でパケット (64 バイト) で送受信しています。データには特定の形式があり、その一部は要求/応答によって異なります。
現在、受信したデータのインタープリターを設計しています。位置ごとにデータを読み取るだけでも問題ありませんが、さまざまな応答形式がある場合はそれほどクールには見えません。私は現在、その目的のためにいくつかの構造体を作成することを考えていますが、パディングがどうなるかわかりません。
多分もっと良い方法がありますか?
関連している:
構造体または共用体を使用する必要があります。接続の両側でデータが適切にパックされていることを確認する必要があります。また、接続のどちらかの側が異なるバイト オーダーで実行されている可能性がある場合は、両端でネットワーク バイト オーダーとの間で変換することをお勧めします。エンディアン。
例として:
#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);
ここでは、エンディアンとアライメント、および構造体のパッキングについて説明します。
構造体をパックしないと、単語の境界に合わせて配置され、構造体の内部レイアウトとサイズが正しくなくなります。
私はこれまでに数え切れないほどこれを行ってきました。これは非常に一般的なシナリオです。私が事実上常に行っていることがいくつかあります。
利用可能な最も効率的なものにすることについてあまり心配しないでください。
パケットのパックとアンパックに多くの時間を費やすことになった場合は、いつでもより効率的に変更できます。まだ必要なケースに遭遇したことはありませんが、ネットワークルーターを実装していません!
構造体/共用体を使用することはランタイムの点で最も効率的なアプローチですが、いくつかの複雑な問題が伴います: 必要なパケットのオクテット構造に一致するように構造体/共用体をパックするようにコンパイラーを説得し、アラインメントとエンディアンの問題を回避するように働きかけます。 、およびデバッグビルドでサニティチェックを行う機会がまったくないかほとんどないため、安全性の欠如.
私はよく、次のようなものを含むアーキテクチャにたどり着きます。
これらすべてにおいて、変更可能な各フィールドが適切な値に設定されていることを (デバッグ ビルドの場合でも) 確認することができます。大変な作業のように思えるかもしれませんが、無効なフォーマットのパケットを作成することは非常に困難です。事前にパックされたパケットの内容は、デバッガーを使用して目で簡単に確認できます (すべて通常のプラットフォーム固有のフォーマット変数であるため)。
より効率的なストレージ スキームを実装する必要がある場合でも、パフォーマンス コストをほとんど追加せずに、この抽象化にラップすることができます。
データの正確な形式を知らずに、何が最善の解決策であるかを言うのは困難です。ユニオンの使用を検討しましたか?
これは「すぐに使える」ソリューションですが、Pythonコンストラクトライブラリを参照することをお勧めします。
Construct は、データ構造 (バイナリまたはテキスト) の解析と構築のための Python ライブラリです。これは、手続き型のコードではなく、宣言的な方法でデータ構造を定義するという概念に基づいています。より複雑な構造は、より単純なものの階層で構成されています。今日の通常の頭痛の代わりに、解析を楽しくする最初のライブラリです。
構成は非常に堅牢で強力であり、チュートリアルを読むだけで問題をよりよく理解するのに役立ちます. 作成者は、定義から C コードを自動生成する計画も持っているので、一読する価値は間違いなくあります。
ウギーさんに同意。コード生成を使用してこれを行うこともできます。シンプルなデータ定義ファイルを使用してすべてのパケット タイプを定義し、それに対して Python スクリプトを実行して、それぞれのプロトタイプ構造とシリアル化/非シリアル化関数を生成します。