2011-04-14 17 views
4

私はいくつかの構造体が異なるオペレーティングシステム(TCPネットワーク)を介して送信するように定義しました。 定義構造:C言語で正しいパディングとエンディアンでソケット上に構造体を送信

struct Struct1 { uint32_t num; char str[10]; char str2[10];} 
struct Struct2 { uint16_t num; char str[10];} 

typedef Struct1 a; 
typedef Struct2 b; 

データはテキストファイルに保存されます。 データフォーマットのようなある:

  • パイ
  • クラスト

Struct1 Aは3つの別々のパラメータとして格納されています。しかし、struct2は、2番目と3番目の両方の行がchar str []に格納された2つの独立したパラメータです。問題は、複数のネットワークを介してサーバーに書き込むときに、データが正しく受信されないことです。構造内のさまざまなパラメータを分離する多数のスペースがあります。サーバーに書き込むときに、適切な送信と埋め込みを保証するにはどうすればよいですか?データを正しく保存するには(動的バッファまたは固定バッファ)?

書き込みの例:write(fd、&、sizeof(typedef struct a));これは正しいです?

  • 123(、)
  • 0(パイ)
  • 0(クラスト)

正しい出力

123:

問題struct2用側出力を受け取ります(パイ、クラスト)

+0

送信と受信に使用するコードのスニペットを投稿する必要があります。間違っていることは実際には推測できません。 – Mat

+0

[RFC 4506 XDR:外部データ表現標準](http://tools.ietf.org/html/rfc4506.html)で、マシン間の転送用にデータをエンコードする方法について説明しています。 –

答えて

10

write(fd,&a, sizeof(a));が正しくありません。 Cコンパイラは要素間にパディングを導入して正しい整列を確実に行うことができるため、少なくとも移植可能ではありません。 sizeof(typedef struct a)は意味をなさない。

データの送信方法は、プロトコルの仕様によって異なります。特に、プロトコルは、文字列を送信するための広範な方法を定義しています。一般的にはstructメンバーを別々に送信することが最も安全です。書き込みのための複数の呼び出しか、writev(2)のいずれかです。簡単な方法は、それぞれの二つの機能を記述することです

struct iovec v[2]; 
v[0].iov_base = &foo.a; 
v[0].iov_len = sizeof(uint32_t); 
v[1].iov_base = &foo.b; 
v[1].iov_len = sizeof(uint16_t); 
writev(fp, v, 2); 
+1

2番目のエントリのインデックスをv – dubnde

+0

htonsに更新し、htonlは16および32ビット整数をネットワーク・エンディアンに変換するためのフレンドです。 ntohsとntohlはそれらを元に戻します。 –

+0

@ larsmans次に、データを "write(sockfd、&v [0]、htons(sizeof(v [0]))")構造体に読み込むためのコードスニペットを示します。 ' –

1

:たとえば、foo.afoo.bはすでに正しいエンディアンを持っているネットワーク上で

struct { uint32_t a; uint16_t b; } foo; 

を送信するために、あなたのような何かをするだろう構造体:テキスト表現から構造体への変換、構造体からテキストへの変換を行う変換。次に、あなたはネットワーク上でテキストを送信し、受信側ではそれをあなたの構造に変換します。そうすればエンディアンは重要ではありません。

3

ネットワークを介した送信構造は難しいです。次の問題があります。

  1. バイトエンディアンで整数が発生します。
  2. コンパイラによって埋め込みが導入されました。
  3. 文字列の解析(文字列の境界の検出など)。

パフォーマンスが目標でない場合は、送受信する各構造体(ASN.1、XMLまたはカスタム)のエンコーダとデコーダを作成することをお勧めします。パフォーマンスが本当に必要な場合は、エンディアン(つまりネットワークバイト の順)を修正し、整数がそれらの構造体に格納されるようにして、構造体を使用して(1)を解決し、(2)コンパイラを修正し、プラグマまたは属性を使用して「パックされた」構造体を実行します。例えば

GCCは使用属性(()はパック)など:

struct mystruct { 
    uint32_t a; 
    uint16_t b; 
    unsigned char text[24]; 
} __attribute__((__packed__)); 

(3)を解くことは容易ではありません。ヌル終了文字列をネットワークプロトコル で使用すると、それらが存在するかどうかによって、コードがいくつかの攻撃に対して脆弱になります。文字列が必要な場合は、上記のような適切なエンコーディング方法を使用します。

+0

これはどのようにサーバーに送信(書き込み)されますか?書く(fd、______、sizeof(mystruct))? –

+0

確かに。この手法は、低レベルのドライバではかなり使用されます。 – Nikos

1

ネットワーク上のバイナリ整数の移植性を保証する変換関数があります。 htons、htonl、ntohs、ntohlを使用して、16ビットと32ビットの整数をホストからネットワークバイトオーダーに変換したり、その逆に変換したりします。