[英]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.