2010-02-13 16 views
5

Quiero saber cómo leer una estructura dentro de una estructura mediante la función unpack de php. Cuando obtengo un paquete IS_MCI, verifico su Tipo para asegurarme de que sea igual a ISP_MCI, y luego verifico NumC para descubrir cuántas estructuras CompCar hay dentro de este paquete. El problema es tratar de descomprimir estos contenidos en una matriz a través de una sola función. Siempre obtengo una compensación indefinida. Entonces, estoy buscando nuevos ojos sobre el asunto.Lectura de una estructura dentro de una estructura mediante la función de desempaquetado de PHP

¿Cómo manejarías este paquete?

La estructura en cuestión es la siguiente:

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) 
}; 
+1

¿Se puede publicar la función que le proporciona la compensación no válida? – Eineki

+0

Aparentemente era el concepto que no comprendí. VolkerK lo explicó completamente en su respuesta. Gracias por mirar @ mi pregunta. –

Respuesta

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

impresiones

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 
       ) 

     ) 

) 

Ahora, que el código hace algunos supuestos que puede que no desee dar por sentado (es decir, añadir un montón más manejo de error/lectura de datos).

  • Asume que el paquete ($ msg) se ha leído completamente antes de que se ejecute el código. Es posible que desee leer solo las partes que necesita actualmente (no necesita substr()). O, por lo menos, prepárese para que el mensaje llegue en varios fragmentos.
  • También da por sentado los parámetros size/num, es decir, no verifica si los valores son factibles y si hay suficientes datos disponibles. Eso es definitivamente algo que tienes que cambiar. Size debe estar entre 0 ... 228, NumC debe estar entre 0 ... 8 y ambos valores deben coincidir, y así sucesivamente.
  • También eche un vistazo más de cerca a los identificadores de formato que he usado en unpack(). Para word He usado v que significa "unsigned short (siempre 16 bits, byte menos significativo primero) Pero para int He usado l:. 'Firmado larga (siempre 32 bits, máquina de orden de bytes)' . Eso está bien en mi máquina. Pero buscar en la documentación del protocolo para la endianness de los datos.

el testdata en $ mensaje ha sido tomado del resultado de

__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; 
} 
+0

Gracias, voy a probar y me pondré en contacto con usted. Gracias Señor. –

1

estoy usando esto:


class IS_MCI extends ISP { 
     public $Size; 
     public $Type = ISP_MCI; 
     public $ReqI; 
     public $NumC; 

     public function IS_MCI($data, &$CompCar) { 
       $up = unpack('CSize/CType/CReqI/CNumC', $data); 
       $this->Size = $up['Size']; 
       $this->ReqI = $up['ReqI']; 
       $this->NumC = $up['NumC']; 

       $temp = array(); 

       $p = 4; 
       for ($i = 0; $i NumC; $i++) { 
         $up2 = unpack('SNode/SLap/CPLID/CPosition/CInfo/CSp3/IX/IY/IZ/SSpeed/SDirection/SHeading/sAngVel', substr($data, $p, 28)); 
         $temp[] = new CompCar($up2['Node'],$up2['Lap'],$up2['PLID'],$up2['Position'],$up2['Info'],$up2['Sp3'],$up2['X'],$up2['Y'],$up2['Z'],$ 
         $p += 28; 
       } 
       $CompCar = $temp; 
     } 
} 

y Clase CompCar:


class CompCar { 
     public $xNode;   // current path node 
     public $Lap;   // current lap 
     public $PLID;   // player's unique id 
     public $Position;  // current race position : 0 = unknown, 1 = leader, etc... 
     public $Info;   // flags and other info - see below 
     public $Sp3; 
     public $X;    // X map (65536 = 1 metre) 
     public $Y;    // Y map (65536 = 1 metre) 
     public $Z;    // Z alt (65536 = 1 metre) 
     public $Speed;   // speed (32768 = 100 m/s) 
     public $Direction;  // direction of car's motion : 0 = world y direction, 32768 = 180 deg 
     public $Heading;  // direction of forward axis : 0 = world y direction, 32768 = 180 deg 
     public $AngVel;   // signed, rate of change of heading : (16384 = 360 deg/s) 

     public $SpeedKPH;  // speed in kph 
     public $SpeedMPH;  // speed in mph 
     public $DirectionC;  // Direction calculated to degrees 
     public $HeadingC;  // Heading calculated to degrees 
     public $AngVelC;  // Calculated 

     // ADDED: 
     public $SpeedMS;    // speed in mps 

     public function __construct($xNode,$Lap,$PLID,$Position,$Info,$Sp3,$X,$Y,$Z,$Speed,$Direction,$Heading,$AngVel) { 
       $this->xNode = $xNode; 
       $this->Lap = $Lap; 
       $this->PLID = $PLID; 
       $this->Position = $Position; 
       $this->Info = $Info; 
       $this->Sp3 = $Sp3; 
       $this->X = $X; 
       $this->Y = $Y; 
       $this->Z = $Z; 
       $this->Speed = $Speed; 
       $this->Direction = $Direction; 
       $this->Heading = $Heading; 
       $this->AngVel = $AngVel; 

       $this->doCalcs(); 
     } 

     private function doCalcs() { 
       // Speed Calc 
       $old = $this->Speed; 
       $this->SpeedKPH = ($old * (100/32768)) * 3.6; 
       $this->SpeedMPH = $this->SpeedKPH * 0.6215; 

       $this->SpeedKPH = floor($this->SpeedKPH); 
       $this->SpeedMPH = floor($this->SpeedMPH); 
       $this->SpeedMS = $this->SpeedKPH/3.6; 

       // Direction 
       $this->DirectionC = CompCar::degrees($this->Direction); 

       // Heading 
       $this->HeadingC = CompCar::degrees($this->Heading); 

       // Angle Calcs 
       $this->AngVelC = $this->AngVel * 180/8192; 
     } 

     public static function degrees($input) { 
       $input = $input/65535 * 360; 
       //$input = 360 - floor($input); 
       $input = floor(360 - $input); 
       return $input; 
     } 

} 

Y todo lo que está funcionando bien!

+0

Estoy tomando una ruta ligeramente diferente, ¡pero apruebo esta publicación! +1. –

Cuestiones relacionadas