ネットワークでバイト順を安全に無視できますか?


24

クライアントがWindows上で実行され、サーバーがおそらくLinux上で実行されるサーバークライアントアプリケーションを開発しています。後でクライアントをMacとLinuxに移植するかもしれませんが、まだではありません。

最近のすべてのホームコンピューターは、リトルエンディアンで実行されます。私はしばらくグーグルで検索しましたが、ビッグエンディアンで動作するデバイスのリストを実際に見つけることができませんでした。私の知る限り、一部のMotorolaチップは依然としてビッグエンディアンを使用し、おそらく一部の携帯電話を使用します(アプリをスマートフォンに移植する予定はないので、これは私には関係ありません)。サーバーとクライアントの両方がリトルエンディアンで実行されていることがわかっているのに、読み取り書き込みのために、すべての整数、すべてのショート、すべてのフロート、ダブルなどのバイトを再配置するのはなぜですか?

それはただ行う必要のない作業です。だから、私の質問は次のとおりです:エンディアンを安全に無視して、リトルエンディアンのデータを送信できますか?欠点は何ですか?


4
マシンは、通常/標準のビッグエンディアンデータではなく、リトルエンディアンデータを受信して​​いるかどうかをどのように知るのでしょうか?
Ixrec

2
ネットワークプロトコルで必要なメタデータと、コード以外のすべての人にとって解釈されないバイトの集まりであるペイロードを区別する必要があります。あなたがあなた自身のネットワークスタックを動かしていないことを願っています。したがって、質問はペイロードに関するものだけであると思いますか?

2
@delnanはい、ペイロードについてのみ話します。もちろん、ネットワークスタック自体とはネットワークバイト順で話します。
tkausl

3
ちょっと考えてみてください:エンディアンネスが懸念される抽象化レベルで作業することは本当に必要ですか?この低レベルの「混乱」をすべてカプセル化する適切なライブラリが存在するプロトコルの使用を検討する価値があるかもしれません。さらに、クライアントを追加することがはるかに簡単になるという追加のボーナスもあります。
godfatherofpolka

1
@tkauslあと2つだけ考えてみましょう。一般的なルールとして、IOは計算に比べて非常に遅いため、より高い抽象化レベルで作業することによって生じるオーバーヘッドはほとんど無視できます。巧妙なリソースプーリングや非同期処理などにより、一部のライブラリがハンドロール実装よりも優れていることさえあります。そのため、まず既存のソリューションを慎重に評価します。さらに、あなたの説明があれば、パフォーマンスよりも拡張性についても考えます。ここでも、より高レベルのプロトコルを使用することでメリットが得られる可能性があります。
godfatherofpolka

回答:


29

...なぜバイトを再配置するのか...サーバーとクライアントの両方がリトルエンディアンで実行されていることをすでに知っているのに?それはただ不必要な作業です。

コードが常にリトルエンディアンアーキテクチャで実行されることを保証できれば、それは不要です。寿命を延ばすつもりなら、ビッグエンディアンのアーキテクチャが「イン」のものになり、それが良い市場であることがわかった今から10年後、十分に証明されたコードを邪魔しないようにするための余分な努力の価値がありますあなたの申請。

ネットワーク標準のバイト順序があります。それはビッグエンディアンですが、プロトコルを設計するときにそれを順守しなければならないということはありません。コードを実行しているシステムの大部分がリトルエンディアンであり、パフォーマンスが重要であることが事前にわかっている場合は、「tkausl標準バイト順序」を宣言し、それに従ってください。通常htons()、必要な順序で物事を配置するために呼び出す場合、htots()リトルエンディアンアーキテクチャでは条件付きで何もコンパイルせず、ビッグエンディアンで再配置するというマクロを記述します。

インバウンドおよびアウトバウンドの変換を行うためのコードを維持することは、実際には大きな努力ではありません。非常に多数のメッセージがある場合は、それらを表現する方法を見つけて、インバウンドおよびアウトバウンドの変換を生成するプログラムを作成してください。


10
when designing your protocolこのオプションは、既存のプロトコルを実装するときではなく、新しいプロトコルを設計するときにのみ存在することを暗黙的に示しているため、言葉遣いは重要です。また、htots(および実際には関数のファミリー全体)の必要性に言及すると、異なるバイト順序を選択することはコードを単純にするためのものではなく、わずかに速くなる可能性があることも明確になります。
カスペルド

4
(非標準が、非常に一般的なこれらの日)の機能がありhtole32()htole16()le16toh()だけでなく、利用可能な機能は、など。これらを宣言するためにインクルードするファイルは、残念ながら標準以下です:<endian.h>または<sys/types.h>プラットフォームによって異なります。
torek

この答えは問題ありませんが、特定のケースでパフォーマンスが重要になる可能性があるという仮定は、事実よりも迷信に基づいているため、おそらく間違った仮定であると思います。
ドックブラウン

1
@DocBrown:私は常に、Xプロトコルが30年間独自のバイトオーダーを選択することをサポートしていることを指摘したいと思います。
Blrfl

7

それはあなたのプロトコルです。

安全に無視することはできません。ただし、安全にラベルを付けることができます。クライアントとサーバーを制御します。プロトコルを制御します。両側が一致するかどうかを知っている限り、ビッグエンディアンかリトルエンディアンかを気にしないのは理にかなっていますか?

これはオーバーヘッドを意味します。ここで、どういうわけかエンディアンをマークする必要があります。そうすれば、何でも読むことができます。

データのオーバーヘッドが不要で、CPUが退屈して何かを探している場合は、conformを使用します。


6

だから、私の質問は次のとおりです。エンディアンを無視して、リトルエンディアンのデータを送信するだけでも安全ですか?

これには2つの解釈があります。

  • あなたはいつもに、アプリケーション/プロトコルを設計する場合1つの送信リトルエンディアン、あなたはエンディアンを無視されません。

  • ネイティブエンディアンが何であれ送受信するようにアプリケーション/プロトコルを設計する場合、同じネイティブエンディアンのプラットフォームでアプリケーションを実行する限り、それらは機能します。

    それは「安全」2ですか?それはあなたが判断することです!しかし、リトルエンディアン、ビッグエンディアン、または...バイエンディアンを使用する一般的なハードウェアプラットフォームは確かにあります。

    参照:

欠点は何ですか?

エンディアンネスを無視することの明らかな欠点は、あなた/ユーザーが異なるネイティブエンディアンネスを持つプラットフォーム間でアプリケーション/プロトコルを実行する必要がある場合、問題が発生することです。アプリケーションが壊れるので、問題を修正するためにアプリケーションを変更する必要があります。また、バージョンの互換性の問題などに対処します。

明らかに、現在の世代のプラットフォームのほとんどはネイティブのリトルエンディアンですが、1)一部のプラットフォームはそうではなく、2)将来何が起こるかしか推測できません。


1-常に...ネイティブビッグエンディアンのプラットフォームを含む。

2-実際、「安全」とはどういう意味ですか?ハードウェアプラットフォームの将来の方向性を予測するように求めている場合...客観的に答えられないのではないかと思います。


3

エンディアンネスだけが考慮事項ではありません。整数のサイズ、送信または受信したい構造体のパッキングなどがあります。

これはすべて無視できます。誰もあなたを強制することはできません。一方、安全で信頼できる方法は、外部形式を文書化してから、プロセッサ、プログラミング言語、およびプログラミング言語の実装に関係なく、外部形式を正しく読み書きするコードを記述することです。

通常、あまりコードではありません。しかし、それには大きな利点があります。コードを読んでいる人は、あなたが無知であると疑ったり、外部データの交換について何も知らず、一般的に信頼できないコードを書いたりしません。


3

Cの標準BSDネットワークスタックにはhton/ ntoh機能(network-to-host/ host-to-network)があり、ネットワークネイティブマシン(ビッグエンディアン)ではno-opに拡張されます。ネットワーク固有のバイトオーダーがリトルエンディアンであるシナリオでは、これらに対応する独自のものが必要になります。

それはそれを行うための堅牢な方法です。

それは型にはまらないだろうが、私はそれで何も悪いことはないと思う。ネットワーク化されたコンピューターは常にバイトストリームを取得し、それらのバイトの解釈方法に関するプロトコルに同意する必要があります。これはほんの一部です。


3

サーバー間でデータを送信するために使用されるさまざまなプロトコルは、リトルエンディアン番号を使用します。

  1. BSON
  2. プロトコルバッファ
  3. Capn Proto

さまざまな形式の詳細についてはhttps://en.wikipedia.org/wiki/Comparison_of_data_serialization_formatsを参照してください一部の形式にはリトルエンディアン番号があり、一部の形式にはビッグエンディアン番号があります。

リトルエンディアン番号に基づいたプロトコルを使用しても、まったく問題はありません。ビッグエンディアンのマシンは、ビッグエンディアンのマシンがビッグエンディアンの数値を読み取ることができるのと同じように、リトルエンディアンの数値を読み取ることができます。多くの人々は、特にリトルエンディアンのマシンでビッグエンディアンの数値をデコードする余分な計算コストを避けるためにそれをしました。

これらの既存のプロトコルのいずれかの上にプロトコルを構築する場合、すでに問題を処理しているので、自分で問題を心配する必要さえありません。ビッグエンディアンプラットフォームでコードを実行する場合、これらのプロトコルを実装するライブラリが自動的に値を正しくデコードするようにします。


2

ビッグエンディアンシステムの一例は、ルーターで使用されるMIPSです。ARMとMIPSはどちらもエンディアンで切り替え可能ですが、多くの場合、MIPSはネットワークハードウェアを簡単にするため、ビッグエンディアンです(単語の最も重要な部分は最初に受け取る部分であり、残りの部分を受け取る前にルーティングの決定を行うことができます)単語全体をバッファリングするのではなく、単語)。

「Linux」の意味に依存しますが、OpenWRTを実行しているルーターのような小規模なシステムでサーバーアプリを実行したい場合は、ビッグエンディアンのサポートを検討する必要があります。

いつものように、仮定を単純化することは、仮定に合わない何かにぶつかるまで、完全に賢明な最適化です。そのような問題に出くわした場合、それらを解くことがどれほど苦痛であるかを言うことができるのはあなただけです。


0

私は答えのどれも十分に正確であるとは思わない。ウィキペディアによると、エンディアンネスは単語を構成するバイトの順序です。

4バイトを取得して、それらをintとして解釈します。リトルエンディアンシステムの場合、バイトは右から左に解釈され、ビッグエンディアンシステムでは逆に解釈されます。明らかに、intを解釈する目的について合意することが重要です。

jsonまたはxmlを使用している可能性のある最新のネットワークプロトコルに少しズームアウトします。これらの形式はいずれも、intを4バイトとして転送しません。受信側でintとして解析されるテキストとしてデータを転送します。

そのため、jsonまたはxmlを使用する場合、エンディアンは重要ではありません。tcpヘッダーにはビッグエンディアンを使用する必要があるため、ネットワークバイトオーダーと呼ばれますが、ほとんどのプログラマーは日常的にそれらを台無しにする必要はありません。

最も広く使用されている今日、ほとんどエンコードもあることをhapppensたUTF-8であるエンディアンに関する問題への免疫

だから私はイエスと言うでしょう。utf-8を使用して転送されたテキストベースの形式を使用する場合、エンディアンを無視しても安全です。


2つの反対票とコメントなし。すばらしいです。
エスベンスコフペダーセン

1
私は支持者ではありませんでしたが、この答えは完全に有効な質問を無視/却下しているようです。一部のプロトコルがテキストベースであるという理由だけで、すべてのプロトコルがそうであることを意味するわけではありません。
ピーターグリーン

2
これは、ペイロード形式が基礎となるプロトコルとは無関係であるという事実に触れるため、私はこれを支持しました。メイクアップの問題を掘り下げるのが大好きな人もいます。
ズデネク

0

ビッグエンディアンのシステムは、もうすぐ出て行くようです。従来のUNIXの多くはビッグエンディアンを使用していましたが、x86上のLinuxを支持して長年衰退しています。

アームはバイエンディアンですが、ビッグエンディアンのバリアントはほとんど見られないようです。

mipsは両方のバリアントに存在します。ビッグエンディアンの変種は、ほとんどがネットワーキングアプリケーションで見られます(歴史的な理由から、インターネットプロトコルは通常ビッグエンディアンを使用します)。

ppcは伝統的に両方のエンディアンをサポートする一部のビッグエンディアンでしたが、IBMは現在64ビットppcのリトルエンディアンモードをプッシュしているようです(最近、ppc64elポートをDebianとUbuntuにプッシュしました)。

sparcは通常ビッグエンディアンですが、再び減少しているようです。

既存のプロトコルを実装する場合、明らかにその仕様に従う必要があります。IETFで新しいプロトコルを祝福したい場合、ビッグエンディアンは既存のプロトコルで既に使用されているため、ビッグエンディアンがより簡単になる可能性がありますが、新しい「グリーンフィールド」プロトコル設計のリトルエンディアンはIMOを使用する方法です。

ビッグエンディアンシステムに移植する必要がある場合を除いて、リトルエンディアンシステムでは何もしないマクロを最初から挿入するか、気にすることはできません。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.