2

完全な背景 (問題を理解するためにこれを理解する必要はありませんが、役立つ場合があります) については、イーサネット経由でデータを送信する CLI プログラムを作成しており、VLAN タグと優先度タグをイーサネット ヘッダーに追加したいと考えています。

私が直面している問題は、3 つの小さい値から構築された単一の 16 ビット整数値があることです: PCP3 ビット長 (つまり 0 から 7)、DEI1 ビット長、そしてVLANID12 ビット長 (0 から 4095) です。PCP一緒にDEI最初の 4 ビット ニブルを形成し、VLANID加算からの 4 ビットで最初のバイトを完成させ、残りの 8 ビットでVLANID整数の 2 番目のバイトを形成します。

11123333 33333333

1 ==PCPビット、2 ==DEIビット、3 ==VLANIDビット

PCP== 5 (バイナリでは 101、DEI== 0、および== 164、バイナリでは 0000 10100011) のふりVLANIDをしましょう。まず、次のようにこれらの値をまとめてコンパイルする必要があります。

10100000 10100101

私が直面する問題は、この整数をバッファーにコピーしてワイヤー (イーサネット媒体) にエンコードするときに、ビットの順序が次のように変化することです (整数をワイヤーにコピーする前にバイナリで出力し、wireshark を使用して比較するためにネットワーク上でキャプチャします):

メモリ内のビット順:abcdefgh 87654321

ワイヤ上のビット順序:8765321 abcdefgh

ここには2つの問題があります。

  • 1つ目は、3つの小さい整数を「くっつけて」2バイト整数を作成することです
  • 2 つ目は、ビットの順序がワイヤ上で正しくエンコードされることを保証することです (したがって、バイトは逆順ではありません)。

明らかに、私はこのコードでこれを達成しようとしましたが、私は本当に深みがなく、これまでに行ったことを投稿して誰かがそれを変更する方法を提案するのではなく、誰かの提案を最初から見たいと思っています必要な機能を、おそらく読みにくく、長々とした方法で実行します。

4

1 に答える 1

3

問題は、ビット順ではなくバイト順です。メモリ内のビットは個別にアドレス指定できないため、実際には順序がありません。伝送メディアは、伝送された個別のエンティティ (この場合はオクテット) が送信されたのと同じ形で到着することを保証する責任があります。

一方、バイトはアドレス指定可能であり、送信メディアは、並べ替えを行う必要のないバイト文字列を送信しているのか、それとも受信側で 1 バイトの順序付けが必要な 4 バイトの整数を送信しているのかわかりません。送信者の。

このため、ネットワーク プロトコルには、すべての送信者と受信者がデータを変換する必要がある宣言された「バイト順序」があります。このようにして、異なるネイティブ バイト順のネットワーク ホストによって透過的にデータを送信および取得できます。

POSIX では、必要な変換を行うための関数がいくつか定義されています。

#include <arpa/inet.h>

uint32_t htonl(uint32_t hostlong);
uint16_t htons(uint16_t hostshort);
uint32_t ntohl(uint32_t netlong);
uint16_t ntohs(uint16_t netshort);

「n」と「h」は「ネットワーク」と「ホスト」を表します。そのため、htonl は 32 ビット量をホストのメモリ内バイト順序からネットワーク インターフェイスのバイト順序に変換します。

ネットワーク経由で送信するバッファを準備するときはいつでも、その中の各値をホストのバイト順からネットワークのバイト順に変換する必要があり、受信データのバッファを処理しているときはいつでも、その中のデータを変換する必要がありますネットワークの順序付けからホストの順序付けまで。

struct { uint32_t i; int8_t a, b; uint16_t s; } sent_data = {100000, 'a', 'b', 500};

sent_data.i = htonl(sent_data.i);
sent_data.s = htons(sent_data.s);

write(fd, &sent_data, sizeof sent_data);

// ---

struct { uint32_t i; int8_t a, b; uint16_t s; } received_data;

read(fd, &received_data, sizeof received_data);

received_data.i = ntohl(received_data.i);
received_data.s = ntohs(received_data.s);

assert(100000 == received_data.i && 'a' == received_data.a &&
       'a' == received_data.b && 500 == received_data);

上記のコードは、送信者と受信者の両方が互換性のある char エンコーディングを使用している (たとえば、両方とも ASCII を使用している)、両方とも 8 ビットのバイトを使用している、バイトを考慮した後に互換性のある数値表現を持っているなど、いくつかの仮定を行っていますが、注文など


移植性を気にせず、リモート ホスト上でのみ相互運用するプログラムは、パフォーマンス コストを回避するためにバイト オーダーをスキップする場合があります。すべてのホストが同じバイト順を共有するため、変換する必要はまったくありません。もちろん、プログラムがこれを行い、後で異なるバイト順序のプラットフォームに移植する必要がある場合は、ネットワーク プロトコルを変更するか、プログラムがネットワーク順序でもホストの順序でもないバイト順序を処理する必要があります。 .


今日、唯一の一般的なバイト順序は単純に相互に逆になっています。つまり、hton と ntoh はどちらも同じことを行い、送信と受信の両方に hton を使用することもできます。ただし、コードの意図を伝えるためだけに適切な変換を使用する必要があります。そして、いつの日かあなたのコードが hton と ntoh が交換できない PDP-11 で実行されるかもしれません。

于 2013-11-11T22:51:40.137 に答える