Чтение Структуры В Структуре через PHP's Распаковывает Функцию

Я хочу знать, как читать, структура в структуре через 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)
};

6
задан Mark Tomlin 13 February 2010 в 07:51
поделиться

1 ответ

$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
                )

        )

)

Теперь, этот код делает некоторые предположения, которые вы, возможно, не захотите принимать как должное (т.е. добавить гораздо больше обработки ошибок/читаемых данных).

  • Он предполагает, что пакет ($msg) был полностью прочитан до выполнения кода. Возможно, вы захотите прочитать только те части, которые вам нужны в данный момент (тогда не понадобится substr()). Или, по крайней мере, будьте готовы к тому, что сообщение может прийти несколькими частями.
  • Он также принимает параметры size/num как должное, т.е. не проверяет, являются ли эти значения выполнимыми и достаточно ли данных доступно. Это определенно то, что вы должны изменить. Size должен быть между 0...228, NumC должен быть между 0...8, оба значения должны подходить друг другу и так далее.
  • Также присмотритесь к идентификаторам формата, которые я использовал в функции unpack(). Для 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;
}
3
ответ дан 17 December 2019 в 07:04
поделиться
Другие вопросы по тегам:

Похожие вопросы: