質問
皆さん、C/ネットワーキングの初心者からの質問です...
私は C でソケットプログラミングを行っており、バイトオーダーの問題と格闘しようとしています。リクエスト (送信) は正常ですが、データを受信するとバイトの順序がすべて狂います。こんな感じから始めます…
char * aResponse= (char *)malloc(512);
int total = recv(sock, aResponse, 511, 0);
この応答を処理するとき、各 16 ビット ワードのバイトが逆になっているように見えます (UDP を使用しています)。このようなことをしてそれを修正しようとしました...
unsigned short * _netOrder= (unsigned short *)aResponse;
unsigned short * newhostOrder= (unsigned short *)malloc(total);
for (i = 0; i < total; ++i)
{
newhostOrder[i] = ntohs(_netOrder[i]);
}
データを short として扱うときはこれで問題ありませんが、ポインタを char に再度キャストすると、バイトが逆になります。私の何が間違っているのでしょうか?
ありがとう!
解決
OK、2つの異なるレベルであなたがやっていることには問題があるようです。ここでの混乱の一部は、ポインタの使用法、ポインタが指すオブジェクトの種類、そしてポインタが指すメモリ内の値のエンコードの解釈に起因しているようです。
メモリ内のマルチバイト エンティティのエンコードは、エンディアンと呼ばれるものです。2 つの一般的なエンコーディングは次のように呼ばれます。 リトルエンディアン (LE) と ビッグエンディアン (なれ)。LE では、short などの 16 ビット量が最下位バイト (LSB) から先にエンコードされます。BE では、最上位バイト (MSB) が最初にエンコードされます。
慣例により、ネットワーク プロトコルは通常、「ネットワーク バイト オーダー」(NBO) と呼ばれるものにエンコードします。これも BE と同じです。ビッグ エンディアン プラットフォームでメモリ バッファを送受信している場合、変換の問題は発生しません。ただし、コードは BE 規約に依存したプラットフォームになります。LE と BE の両方のプラットフォームで正しく動作する移植可能なコードを作成したい場合は、プラットフォームのエンディアン性を前提としないでください。
エンディアンの移植性を実現することが、次のようなルーチンの目的です。 ntohs(), ntohl(), htons(), 、 そして htonl(). 。これらの関数/マクロは、送信側と受信側で必要な変換を行うために、特定のプラットフォーム上で定義されます。
- htons() - short 値をホスト順序からネットワーク順序に変換します (送信用)
- htonl() - Long値をホスト順からネットワーク順に変換(送信用)
- ntohs() - short 値をネットワーク順序からホスト順序に変換します (受信後)
- ntohl() - Long 値をネットワーク順序からホスト順序に変換します (受信後)
文字にキャストバックする際のメモリへのアクセスに関するコメントは、メモリ内のエンティティの実際の順序には影響を与えないことを理解してください。つまり、バッファに一連のバイトとしてアクセスすると、BE マシンか LE マシンかに関係なく、実際にメモリにエンコードされた順序でバイトが表示されます。したがって、受信後に NBO エンコードされたバッファを見ている場合、常に MSB が最初になります。BE マシンを使用している場合、ホスト順序に変換し直した後で出力バッファを見ると、バイト順序は変更されていません。逆に、LE マシンでは、変換されたバッファ内のバイトはすべて反転されます。
最後に、変換ループ内で変数 total
バイトを指します。ただし、次のようにバッファにアクセスしています shorts
. 。ループ ガードは次のようなものであってはなりません。 total
, ただし、次のようにする必要があります。
total / sizeof( unsigned short )
それぞれのダブルバイトの性質を考慮して short
.
他のヒント
私は再びバイトが逆転しているのcharへのポインタをキャストした場合、私はしかし、短いなどのデータを処理していたときにこのはOK働くます。
それは私が期待するものです。
私が間違って何をしているのですか?
あなたは、送信者が送信したものを知っている必要があります。データは(やる)(逆転必要はありません)バイト、または短絡やlong型であるかを知っている。
。 ntohs
、htons
に関連したチュートリアル、およびhtons
APIのグーグルます。
これは何を表すのかaResponse
はっきりしない(文字の文字列を?構造体?)。 エンディアンには数値のみではなく、char
sに関連します。また、送信者側では、全ての数値は、ネットワークバイト順(hton*
)にホストから変換されていることを確認する必要があります。
アパート(私はすでに答えたと思います)あなたの元の質問から、あなたは、のmalloc関数の声明を見ている必要があります。 のmalloc関数の割り当てバイトと符号なしshortは2バイトである可能性が最も高いです。
あなたの文は次のようになります。
unsigned short *ptr = (unsigned short*) malloc(total * sizeof(unsigned short));
ネットワークバイトオーダーを使用すると、あなたはそれが意味を作りたい場合はリトルエンディアンに変換する必要がありますので、ビッグエンディアンですが、それはそれは大騒ぎをするべきではありませんのみのアレイであれば、どのように送信者は、それがデータだ送信ん?
シングルバイトのために我々はバイト順序を気にしないことがあります。