簡體   English   中英

在C ++中發出接收和存儲數據的問題

[英]Issue receiving and storing data in C++

我已經用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()時數據存儲不正確。 請有人啟發我。 謝謝。

PS:對不起,我很抱歉。

將結構聲明為打包結構,以避免對齊問題;

在Windows上,使用#pragma pack (1) (請參閱msdn

在gcc上使用__attribute__((packed))

消除對齊問題。 實際上,gcc將支持Windows樣式實用程序以實現兼容性。 看一下:

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

編輯

因此,下面的示例代碼顯示了另一個未改動的結構內的一個打包結構:

在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

結構中的字節必須對齊4個字節。 您必須引入一些備用變量:

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];
};

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM