データ転送プロトコルについて

この記事では、さまざまな非公開データ転送プロトコル(主にアプリケーションセッションレベル)での個人的な非学術的経験を共有したいと思います。



多くの場合、専用のソフトウェア(および、最終的にはボードに配線されたファームウェアとのペアがあります)とのペアリングが必要になります。各メーカーは独自のデータ交換プロトコルを提供します。



適切で適切な、高品質のプロトコルにはどのような特性と機能がありますか?



理想的には、プロトコルは、TCP、UDP、シリアルポート、USB、Bluetooth、デジタル無線信号、さらには鳩メールを介した伝送であろうと、低レベルの相互作用から抽象化される必要があります。 また、すべてが送信データの配信および/または信頼性を保証するわけではないことに注意してください。



小さな免責事項:データの信頼性について言えば、伝送媒体の干渉やその他のエラーによる歪みがないことを意味します。 この記事では、ITセキュリティに関連するテクノロジーのレイヤーについては触れません。 アリスとボブがお互いを信頼し、イブがそれらを止めることができないと仮定します。 (たとえば、同僚の場合、セキュリティ上の問題は、地理的に離れたすべての対話参加者を適切に保護されたVPNに含めることで解決されます。VPNは外部にアクセスできません)



ほとんどのプロトコルは、Q&Aスキームを実装しています。 これは、対話者の各発言に対して同じ意味的な方法で口頭で応答する会話として想像できます。 したがって、対話の参加者は、自分のメッセージが送信され、適切に受信されるという自信を獲得します。 ただし、このスキームはすべてのタスクに受け入れ可能で効果的ではありません。通信の遅延を最小限に抑える必要がある場合、または多くのレプリカのそれぞれに対する応答が過剰と見なされる場合(たとえば、メッセージのデバッグ用)、Start-Stopスキームが実装されます。 「開始」でメッセージを受け取ると、対話者はあなたのレプリカのストリームを注ぎ始め、「停止」という言葉で沈黙します。 ストリームで送信されるメッセージには通常、増分シーケンス番号が付いており、メッセージストリームの処理で問題が発生した場合、それらの1つがスキップされた場合、この番号に対して個別に再要求できます。



すべてのプロトコルは、(データの表示に従って)2つのグループに分けられます: シンボリックバイナリ

私が遭遇した文字プロトコルは、XMLまたはJSON文字列に基づいています。 それらの利点のうち、対話のデバッグ(読みやすさによる)、実装の容易さ(既成のパーサーの可用性)、および悪名高い普遍性に言及できます。

今、欠点について。 明らかに、そのようなプロトコルは非常に冗長であり、有用な情報のごく一部が大規模で非効率的なラッパーに浮かんでいます。 数値情報を転送するときは、文字列表現への変換を処理する必要があります。逆も同様です。 痛い点は、バイナリデータの転送です(そして、それを省くことができるのは良いことですが、場合によっては不可能です)。 プロトコルコンパイラは通常、 Base64を使用して、または16進表記のバイナリ文字列(バイトごとに2文字)を使用してねじれています。

また、同じXMLの完全な仕様は非常に広範囲であり、すべての機能を備えた標準のパーサーはかなり面倒で遅いため、部門やオフィスが最終的に独自のパーサーを作成して使用するのは一般的な慣行であることに注意してください。



もちろん、 特定のタスクでは 、シンボリックプロトコルは、最も効果的ではないにしても、少なくとも完全に受け入れられるオプションですが、さらに先に進みます。



現在、 バイナリプロトコル。 すぐに私たちは鈍器のガリバー戦争を思い出さなければなりません。 個人的に、私はビッグエンディアンに同情します。なぜなら、 私は、リトルエンディアンの「良いもの」の暗黙的なタイピングを考えていません。私の開発環境では、ビッグエンディアンはネイティブです。

バイナリプロトコル(すべてではありませんが、読み書きができると考えるプロトコル)は、コンテナレベルとデータレベルの2つのレベルに分けることができます。 最初のレベルは、データ送信の整合性と信頼性、およびバイトストリームでのメッセージ検出の可用性、そしてもちろんデータレベルのメッセージ自体の格納に対する責任です。 2番目のレベルには、すべてのネットワーク対話が開始された情報を、処理に便利な形式で含める必要があります。 その構造は、主に解決されるタスクに依存しますが、一般的な推奨事項があります(以下について)。



メッセージサイズ(前後の受信データとは無関係に処理できる個別のバイトパケット)は固定されており、 可変です 。 メッセージサイズが固定されていると、すべてがより簡単になります-ヘッダーから一定のバイト数が差し引かれ(後で)、処理のために送信されます。 多くの場合、柔軟性を提供するために、そのようなプロトコルの作成者は、現在のプロトコルの変更用に予約された固定サイズの領域(合計の80%まで)をメッセージに含めます。 私の意見では、これは柔軟性を確保するための最も効果的な方法ではありませんが、まだいくらかの冗長性があります。

可変長のメッセージを検討してください。

ここで、任意のプロトコルでのバイナリメッセージの必須属性- ヘッダー (これはコンテナの前述のレベルです)について、すでに詳しく説明できます。

通常、ヘッダーは一定の部分で始まり、一定の確率で、連続したバイトストリームのメッセージの始まりを検出できます。 明らかに、任意のバイトストリームにこのような定数が現れるリスクがあり、ボリュームを増やすとこのリスクが減少しますが(0123456789VASIA9876543210などの定数に適合しました)、 チェックサム計算に基づいてチェックを使用する方が便利です。

通常、定数の後にはプロトコルのバージョン番号が続きます。これにより、さらに読む必要があるフォーマットを理解できます(そして、このメッセージを処理する能力があるかどうか-突然このバージョンは不明です)。 ヘッダーの次の重要な部分:コンテナーの内容に関する情報。 コンテンツのタイプ(実際には、データ層の同じプロトコルバージョン番号)、その長さ、およびチェックサムが示されます。 この情報があれば、すでに内容を読んで、問題や恐れなく分析を進めることができます。

しかし、すぐではありません! 見出しには、そのチェックサムを含める必要があります( もちろん、チェックサム自体を計算から除外します )-この方法でのみ、ゴミだけでなく有効な見出しを考慮したことを確認できます。 チェックサムが一致しませんでしたか? 下流の新しい見出しの次の始まりを探す必要があります...



歪みのないデータレベルのメッセージをようやく受け取った段階に到達したと想像してください。 その構造は、ネットワーク交換が実装されているシステムのタスクの領域に依存しますが、一般的には、メッセージにはメッセージのタイプに関する情報を含む独自のヘッダーもあります。 メッセージの一般的な詳細(たとえば、「要求セット」、「設定への肯定応答」、「設定への否定応答」、「要求取得」、「応答取得」、「ストリーミングメッセージ」)とメッセージの特定のアプリケーション領域を区別できます。 。 私は天井から例を挙げようとします:

リクエストタイプ:リクエストセット(0x01)

メッセージ宛先モジュール識別子:PowerSupplyModule(0x0A)

メッセージグループID:UPS管理(0x02)

メッセージタイプID:再起動(0x01)

さらに、メッセージ本文には、UPSのアドレスに関する情報が含まれている場合があります。これは、電源管理モジュールが何秒後にこれを再起動する必要があるかなどです。

このメッセージへの応答メッセージは、ヘッダーで0x0A0201が後に続く要求タイプ「肯定的な回答」で受信されることを期待しています。

もちろん、インターワーキングが多数のコマンドを提供しない場合、メッセージタイプのこのような詳細な説明は冗長になる可能性があるため、ToRの要件に基づいてメッセージ構造を形成する必要があります。

また、「ネガティブアンサー」のメッセージにエラーコードが含まれている場合にも役立ちます。そのため、肯定でコマンドに応答することができませんでした。



最後に、アプリケーションインタラクションのトピックは非常に広範であり、時にはh慢(実際には「銀の弾丸」技術がないことを意味します)であり、私が提示するビューは私の仕事経験からの編集に過ぎないことに注意してください国内外の同僚と。 ご清聴ありがとうございました!



更新しました。

私は自分の記事の批評家と話をすることができたので、いわば「ベイトリュブスキー」の観点でこの問題を扱っていることに気付きました。 もちろん、データストレージとデータ転送処理の普遍性に向けたコースがあるため、この点で、シンボリックプロトコル(主にXMLと言えます)は他のソリューションにオッズを与える可能性があります。 しかし、それらを普遍的に適用する試みについては、Virtを引用させてください。

ツールはタスクに適している必要があります。 ツールがタスクを満たさない場合、それに対応する新しいツールを考え出す必要があり、既存のツールを適応させようとしないでください。



All Articles