0

私は C++ でサーバー アプリケーションを作成しました。これは、クライアント アプリケーション (自分で作成したものではありません) からデータのパケットを受信し、そのデータをコンソールに出力します。問題は、パケット本体全体を一度に受信して保存しようとすると、データが正しく保存されないことですが、recv() の複数の呼び出しを使用してパケット本体を受信して​​保存すると、正しく保存されます。

エンディアンに関しては、クライアントとサーバーは両方ともリトル エンディアン マシンで実行され、クライアントはデータをリトル エンディアンとして送信し、サーバーは変換の必要なくそれを読み取ります。

これは、クライアント アプリケーションがサーバー アプリケーションに送信するパケットです。

00 03 23 00 57 6f 57 00  01 0c 01 f3 16 36 38 78
00 6e 69 57 00 42 47 6e  65 00 00 00 00 7f 00 00
01 05 41 44 4d 49 4e

パケットの構造化ビューを次に示します。

cmd             00
error           03
pkt_size        23 00
gamename        57 6f 57 00
version1        01
version2        0c
version3        01
build           f3 16
platform        36 38 78 00
os              6e 69 57 00
country         42 47 6e 65
timezone_bias   00 00 00 00
ip              7f 00 00 01
srp_I_len       05
srp_I           41 44 4d 49 4e

これらは、サーバー アプリケーションによって出力されると予想される結果です。

cmd:            0
error:          3
pkt_size:       35
gamename:       5730135
version1:       1
version2:       12
version3:       1
build:          5875
platform:       7878710
os:             5728622
country:        1701726018
timezone_bias:  0
ip:             127 0 0 1
srp_I_len:      5
srp_I:          ADMIN

これが私が問題を抱えているコードです:

struct packet{
    uint8   cmd;
    uint8   error;
    uint16  pkt_size;
    uint32  gamename;
    uint8   version1;
    uint8   version2;
    uint8   version3;
    uint16  build;
    uint32  platform;
    uint32  os;
    uint32  country;
    uint32  timezone_bias;
    uint8   ip[4];
    uint8   srp_I_len;
    uint8   srp_I[16];
};

packet data;
recv(clientSocket, &data.cmd, 4, 0); // Receive packet header
recv(clientSocket, &data.gamename, 46, 0); // Receive packet body

printf("%d\n", data.cmd);
...
printf("%s\n", data.srp_i);

結果:

cmd:            0
error:          3
pkt_size:       35
gamename:       5730135
version1:       1
version2:       12
version3:       1
build:          13846 (this is where it all goes wrong)
platform:       1466527232
os:             1850163712
country:        101
timezone_bias:  35512
ip:             1 5 65 68
srp_I_len:      77
srp_I:          IN

コードを次のように変更すると:

recv(clientSocket, &data.cmd, 4, 0); // Receive packet header
recv(clientSocket, &data.gamename, 7, 0); // Receive packet body
recv(clientSocket, &data.build, 39, 0); // Receive packet body

結果:

... same expected results
build:          5875 (fixed)
platform:       1768816760 (goes all wrong here instead)
os:             1195507799
country:        25966
timezone_bias:  8323072
ip:             0 1 5 65
srp_I_len:      68
srp_I:          MIN

コードに最後の調整を加えると、次のようになります。

recv(clientSocket, &data.cmd, 4, 0); // Receive packet header
recv(clientSocket, &data.gamename, 7, 0); // Receive packet body
recv(clientSocket, &data.build, 2, 0); // Receive packet body
recv(clientSocket, &data.platform, 37, 0); // Receive packet body

結果:

... same expected results
build:          5875
platform:       7878710
os:             5728622
country:        1701726018
timezone_bias:  0
ip:             127 0 0 1
srp_I_len:      5
srp_I:          ADMIN

recv() を複数回呼び出すことで、期待どおりにデータを受信して​​格納します。recv() を 2 回呼び出すだけで、データが正しく保存されない理由がまったくわかりません。誰か、教えてください。ありがとうございました。

PS: 醜いモンスター投稿で申し訳ありません。

4

2 に答える 2

1

アラインメントの問題を回避するために、構造体をパック構造体として宣言します。

Windows での使用#pragma pack (1)( msdnを参照)

gcc の使用について__attribute__((packed))

アライメントの問題を取り除きます。実際、gcc は互換性のために Windows スタイルのプラグマをサポートします。見て:

http://gcc.gnu.org/onlinedocs/gcc/Structure_002dPacking-Pragmas.html

編集

したがって、以下のコード例は、別の未処理の構造内に 1 つのパックされた構造を示しています。

x86_64 ビット プラットフォームでコンパイルした場合:

#include <iostream>
#include <stdint.h>
#include <string.h>

using namespace std;


uint8_t input[] = {
    0x00,  0x03,  0x23,  0x00,  0x57,  0x6f,  0x57,  0x00,
    0x01,  0x0c,  0x01,  0xf3,  0x16,  0x36,  0x38,  0x78,
    0x00,  0x6e,  0x69,  0x57,  0x00,  0x42,  0x47,  0x6e,
    0x65,  0x00,  0x00,  0x00,  0x00,  0x7f,  0x00,  0x00,
    0x01,  0x05,  0x41,  0x44,  0x4d,  0x49,  0x4e
};

struct __attribute__((packed)) packet{
    uint8_t   cmd;
    uint8_t   error;
    uint16_t  pkt_size;
    uint32_t  gamename;
    uint8_t   version1;
    uint8_t   version2;
    uint8_t   version3;
    uint16_t  build;
    uint32_t  platform;
    uint32_t  os;
    uint32_t  country;
    uint32_t  timezone_bias;
    uint8_t   ip[4];
    uint8_t  srp_I_len;
    uint8_t  srp_I[16];

};

struct data {
    long int foo;
    short a;
    uint8_t b;
    struct packet p;
    uint32_t bar;
};

int main() {
    struct packet p;
    struct data d;

    cout << "in: " << sizeof(input) << ", d: " << sizeof (d) << ", p: " << sizeof(p) << " d.p: " << sizeof(d.p) << endl;
    memset(&p, 0, sizeof(p));
    memcpy(&p, input, sizeof(input));
    cout << (int) p.srp_I_len << endl;
    cout << p.srp_I  << endl;
}

$./foo
in: 39, d: 72, p: 50 d.p: 50
5
ADMIN
于 2013-05-18T18:42:39.413 に答える
0

The bytes in the structure must be aligned to 4 bytes. You have to introduce some spare variables:

struct packet{
    uint8   cmd;
    uint8   error;
    uint16  pkt_size;
    uint32  gamename;
    uint8   version1;
    uint8   version2;
    uint8   version3;
    uint8   spare1;
    uint16  build;
    uint8   spare2;
    uint8   spare3;
    uint32  platform;
    uint32  os;
    uint32  country;
    uint32  timezone_bias;
    uint8   ip[4];
    uint8   srp_I_len;
    uint8   spare4[3];
    uint8   srp_I[16];
};
于 2013-05-18T18:36:06.460 に答える