2

ソケット接続を確立できる標準クライアント (telnet クライアントなど) と通信するサーバーを作成しようとしています。

もちろん、ネットワークのバイト順を気にする必要はありませんでした。

ntohs、ntohl、htons、htonl 関数に精通しています。16 ビットまたは 32 ビットの int を転送する場合、または送信される文字列の文字が 2 バイトまたは 4 バイトの倍数である場合は、これらだけで十分です。

次のような文字列を操作する関数を作成したいと思います。

str_ntoh(char* net_str, char* host_str, int len)
{
    uint32_t* netp, hostp;
    netp = (uint32_t*)&net_str;
    for(i=0; i < len/4; i++){
         hostp[i] = ntoh(netp[i]);
    }
}

または似たようなもの。上記は、wordsize が 32 ビットであることを前提としています。送信側マシンのワードサイズが 16 ビットでないか、64 ビットでないかはわかりません。

telnet などのクライアント プログラムの場合、データを送信する前に hton* を使用し、データを受信した後に ntoh* を使用する必要がありますね。

編集: 1-char はエンディアンネスが重要ではないバイトであるため、そのことを人々に伝えます:

int main(void)
{
    uint32_t a = 0x01020304;
    char* c = (char*)&a;
printf("%x %x %x %x\n", c[0], c[1], c[2], c[3]);

}

このコード スニペットを実行します。私にとっての出力は次のとおりです。

$ ./a.out
  4 3 2 1

powerPC チップセットのユーザーは '1 2 3 4' を取得する必要がありますが、Intel チップセットのユーザーは、ほとんどの場合、上記の結果を確認する必要があります。

4

4 に答える 4

17

ここで何かが足りないのかもしれませんが、文字列、つまり一連の文字を送信していますか? そうすれば、バイトオーダーを気にする必要はありません。これは整数のビットパターンのみです。文字列内の文字は常に「正しい」順序になっています。

編集:

デリック、あなたのコード例に対処するために、Intel i7 (リトルエンディアン) と古い Sun Sparc (ビッグエンディアン) で次の (わずかに拡張された) バージョンのプログラムを実行しました。

#include <stdio.h>
#include <stdint.h> 

int main(void)
{
    uint32_t a = 0x01020304;
    char* c = (char*)&a;
    char d[] = { 1, 2, 3, 4 };
    printf("The integer: %x %x %x %x\n", c[0], c[1], c[2], c[3]);
    printf("The string:  %x %x %x %x\n", d[0], d[1], d[2], d[3]);
    return 0;
}

ご覧のとおり、整数の出力に実際の char 配列を追加しました。

リトルエンディアン Intel i7 からの出力:

The integer: 4 3 2 1
The string:  1 2 3 4

ビッグエンディアンの Sun からの出力:

The integer: 1 2 3 4
The string:  1 2 3 4

マルチバイト整数は、実際には 2 台のマシンで異なるバイト順で格納されていますが、char 配列内の文字は同じ順序になっています。

于 2009-12-19T21:23:10.660 に答える
4

投稿された関数シグネチャを使用すると、バイトオーダーについて心配する必要はありません。8 ビット文字のみを処理できる char* を受け入れます。1 文字につき 1 バイトの場合、バイト順序の問題は発生しません。

UTF16 または UTF32 エンコーディングで Unicode を送信した場合にのみ、バイト オーダーの問題が発生します。また、送信機のエンディアンと受信機のエンディアンが一致しません。そのための簡単な解決策は、UTF8 エンコーディングを使用することです。これは、ほとんどのテキストがネットワーク経由で送信されるものです。バイト指向であるため、バイトオーダーの問題もありません。または、BOMを送信することもできます。

于 2009-12-19T21:35:22.430 に答える
2

それらを 8 ビット エンコーディングとして送信したい場合 (使用しているという事実は、charこれが必要であることを意味します)、バイト スワップの必要はありません。ただし、非 ASCII 文字の無関係な問題について> 127は、接続の両端で同じ文字が同じように見えるように、すべてのUnicode文字を表すことができ、 ASCII 文字列として安全に扱われます。デフォルトのエンコーディングに基づいて UTF-8 テキストを取得する方法は、使用しているプラ​​ットフォームとライブラリ セットによって異なります。

16 ビットまたは 32 ビットのエンコーディングを送信する場合...バイト オーダー マークを含む 1 文字を含めることができます。これを使用して、もう一方の端で文字のエンディアンを判断できます。または、ネットワークバイトオーダーを想定してhtons()orを使用することもできhtonl()ます。ただし、 を使用したい場合charは、前の段落を参照してください。:-)

于 2009-12-19T21:33:53.080 に答える
1

関数プロトタイプがその動作と一致していないように思えます。char * を渡していますが、それを uint32_t * にキャストしています。さらによく見ると、内容ではなくポインターのアドレスをキャストしているため、予期しない結果が得られるのではないかと心配しています。おそらく、次のほうがうまくいくでしょう。

arr_ntoh(uint32_t* netp, uint32_t* hostp, int len)
  {
  for(i=0; i < len; i++)
    hostp[i] = ntoh(netp[i]);
  }

これは、あなたが実際に持っているのは uint32_t の配列であり、それらすべてに対して ntoh() を実行したいという仮定に基づいています。

これがお役に立てば幸いです。

于 2009-12-20T03:59:29.527 に答える