Я хочу знать, как читать, структура в структуре через php's распаковывают функцию. Когда я получаю пакет IS_MCI, я проверяю, что это - Тип, чтобы удостовериться, что это равно ISP_MCI, и затем я проверяю NumC для обнаружения сколько структур CompCar, там в этом пакете. Проблема пытается распаковать это содержание в массив через единственную функцию. Я всегда получаю неопределенное смещение. Так, я ищу некоторые новые глаза на вопрос.
Как Вы обработали бы этот пакет?
Рассматриваемая структура - это:
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[8]; // car info for each player, 1 to 8 of these (NumC)
};
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)
};
$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);
prints
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
)
)
)
Теперь, этот код делает некоторые предположения, которые вы, возможно, не захотите принимать как должное (т.е. добавить гораздо больше обработки ошибок/читаемых данных).
Size
должен быть между 0...228, NumC должен быть между 0...8, оба значения должны подходить друг другу и так далее. word
я использовал v
, что означает "беззнаковое короткое число (всегда 16 бит, little endian порядок байт)". Но для int
я использовал l
: "signed long (всегда 32 бит, машинный порядок байт)". Это нормально на моей машине. Но поищите в документации к протоколу эндианальность данных. Тестовые данные в $msg были взяты из результата
__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;
}