2010-02-13 14 views
5

Voglio sapere come leggere una struttura all'interno di una struttura tramite la funzione unpack di php. Quando ottengo un pacchetto IS_MCI, controllo che sia Type per assicurarmi che sia uguale a ISP_MCI, quindi controllo NumC per scoprire quante strutture CompCar ci sono all'interno di questo pacchetto. Il problema è cercare di decomprimere questi contenuti in un array tramite un'unica funzione. Ricevo sempre un offset indefinito. Quindi, sto cercando dei nuovi occhi sull'argomento.Lettura di uno Struct all'interno di un Struct tramite la funzione Unpack di PHP

Come gestiresti questo pacchetto?

La struct in questione è questo:

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

È possibile pubblicare la funzione che fornisce l'offset non valido? – Eineki

+0

Apparentemente era il concetto che non avevo afferrato. VolkerK lo ha spiegato abbastanza chiaramente nella sua risposta. Grazie per aver guardato @ mia domanda. –

risposta

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

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

Grazie, testerò e tornerò da te. Grazie Signore. –

1

Sto usando questo:


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; 
     } 
} 

e Classe 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; 
     } 

} 

E tutto sta funzionando bene!

+0

Sto seguendo un percorso leggermente diverso, ma approvo questo post! +1. –