$msg =
chr(0x20) // Size = 32 (4+1*28)
. chr(0x1) // Type = 1
. chr(0x0) // ReqI=0
. chr(0x1) // NumC=1
. chr(0x1) . chr(0x0) // node=1
. chr(0x2) . chr(0x0) // lap=2
. chr(0x3) // puid=3
. chr(0x5) // pos=5
. chr(0x10) // info=16
. chr(0x0) //sp3=0
. chr(0x0) . chr(0x0) . chr(0x1) . chr(0x0) // x=65536
. chr(0x0) . chr(0x0) . chr(0x2) . chr(0x0) // y=65536*2
. chr(0x0) . chr(0x0) . chr(0x3) . chr(0x0) // z=65536*3
. chr(0x0) . chr(0x20) // speed=8192
. chr(0x0) . chr(0x10) // dir=4096
. chr(0x0) . chr(0x8) // heading=2048
. chr(0x0) . chr(0x4) // AngVel=1024
;
$IS_MCI = unpack('CSize', $msg);
if (strlen($msg) < $IS_MCI['Size']) {
die("not enough data");
}
$IS_MCI += unpack('CType/CReqI/CNumC', substr($msg, 1));
$IS_MCI['Info'] = array();
for($i=0; $i<$IS_MCI['NumC']; $i++) {
$data = substr($msg, 4+($i*28), 28);
$IS_MCI['Info'][] = unpack('vNode/vLap/CPLID/CPosition/CInfo/CSp3/lX/lY/lZ/vSpeed/vDirection/vHeading/sAngVel', $data);
}
print_r($IS_MCI);
stampe
Array
(
[Size] => 32
[Type] => 1
[ReqI] => 0
[NumC] => 1
[Info] => Array
(
[0] => Array
(
[Node] => 1
[Lap] => 2
[PLID] => 3
[Position] => 5
[Info] => 16
[Sp3] => 0
[X] => 65536
[Y] => 131072
[Z] => 196608
[Speed] => 8192
[Direction] => 4096
[Heading] => 2048
[AngVel] => 1024
)
)
)
Ora, che il codice fa alcune ipotesi che non si potrebbe desiderare di dare per scontato (cioè aggiungere un sacco più errori/gestione dei dati letti).
- Si presume che il pacchetto ($ msg) sia stato letto completamente prima dell'esecuzione del codice. Potresti voler leggere solo le parti che ti servono al momento (non c'è bisogno di substr() quindi). O almeno preparati a capire che il messaggio può arrivare in diversi blocchi.
- Anche i parametri size/num sono concessi, ovvero non controlla se i valori sono fattibili e sono disponibili dati sufficienti. Questo è sicuramente qualcosa che devi cambiare.
Size
deve essere compreso tra 0 ... 228, NumC deve essere compreso tra 0 ... 8 ed entrambi i valori devono combaciare e così via.
- Dai un'occhiata anche agli identificatori di formato che ho usato in unpack(). Per
word
Ho usato v
che sta per "unsigned short (sempre a 16 bit, poco ordine endian byte) Ma per int
ho usato l
:. "Firmato lunga (sempre a 32 bit, macchina ordine dei byte)" . Va bene sulla mia macchina. Ma cercare la documentazione del protocollo per la endianness dei dati.
il testdata a $ msg è stata presa dal risultato di
__declspec(align(1)) struct CompCar // Car info in 28 bytes - there is an array of these in the MCI (below)
{
word Node; // current path node
word Lap; // current lap
byte PLID; // player's unique id
byte Position; // current race position : 0 = unknown, 1 = leader, etc...
byte Info; // flags and other info - see below
byte Sp3;
int X; // X map (65536 = 1 metre)
int Y; // Y map (65536 = 1 metre)
int Z; // Z alt (65536 = 1 metre)
word Speed; // speed (32768 = 100 m/s)
word Direction; // direction of car's motion : 0 = world y direction, 32768 = 180 deg
word Heading; // direction of forward axis : 0 = world y direction, 32768 = 180 deg
short AngVel; // signed, rate of change of heading : (16384 = 360 deg/s)
};
__declspec(align(1)) struct IS_MCI // Multi Car Info - if more than 8 in race then more than one of these is sent
{
byte Size; // 4 + NumC * 28
byte Type; // ISP_MCI
byte ReqI; // 0 unless this is a reply to an TINY_MCI request
byte NumC; // number of valid CompCar structs in this packet
CompCar Info[1]; // example: one element, fixed
};
int _tmain(int argc, _TCHAR* argv[])
{
struct IS_MCI mci = {
32, 1, 0, 1,
{ 1, 2, 3, 5, 16, 0, 65536, 65536*2, 65536*3, 8192, 4096, 2048, 1024 }
};
WSADATA wsaData;
WORD wVersionRequested = MAKEWORD(2, 2);
int err = WSAStartup(wVersionRequested, &wsaData);
if (err != 0) {
/* Tell the user that we could not find a usable */
/* WinSock DLL. */
return 1;
}
SOCKET s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr("127.0.0.1");
addr.sin_port = htons(8081);
if (0!=connect(s, (SOCKADDR*) &addr, sizeof(addr))) {
printf("%X ", WSAGetLastError());
return 0;
}
send(s, (const char*)&mci, sizeof(mci), 0);
shutdown(s, SD_BOTH);
closesocket(s);
return 0;
}
È possibile pubblicare la funzione che fornisce l'offset non valido? – Eineki
Apparentemente era il concetto che non avevo afferrato. VolkerK lo ha spiegato abbastanza chiaramente nella sua risposta. Grazie per aver guardato @ mia domanda. –