2010-02-13 3 views
5

Je souhaite savoir comment lire une structure dans une structure via la fonction unpack de php. Quand je reçois un paquet IS_MCI, je vérifie que c'est Type pour m'assurer qu'il est égal à ISP_MCI, puis je vérifie NumC pour savoir combien de structures CompCar il y a dans ce paquet. Le problème est d'essayer de décompresser ces contenus dans un tableau via une seule fonction. Je reçois toujours un décalage indéfini. Donc, je cherche des yeux frais sur le sujet.Lecture d'une structure dans une structure via la fonction de décompression de PHP

Comment géreriez-vous ce paquet?

La struct en question est la suivante:

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

Pouvez-vous publier la fonction qui vous donne le décalage invalide? – Eineki

+0

C'était apparemment le concept que je n'ai pas compris. VolkerK l'a expliqué tout à fait dans sa réponse. Merci d'avoir regardé @ ma question. –

Répondre

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

impressions

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 
       ) 

     ) 

) 

Maintenant, ce code fait certaines hypothèses que vous voudrez peut-être de ne pas prendre pour acquis (c.-à ajouter beaucoup plus erreur/gestion des données de lecture).

  • Il suppose que le paquet ($ msg) a été complètement lu avant l'exécution du code. Vous pourriez vouloir lire seulement les parties dont vous avez actuellement besoin (pas besoin de substr() alors). Ou le moins être préparé que le message peut arriver en plusieurs morceaux.
  • Il prend également les paramètres size/num pour acquis, c'est-à-dire qu'il ne vérifie pas si les valeurs sont réalisables et si suffisamment de données sont disponibles. C'est définitivement quelque chose que vous devez changer. Size doit être compris entre 0 et 228, NumC doit être compris entre 0 et 8 et les deux valeurs doivent s'emboiter et ainsi de suite.
  • Regardez également de plus près les identifiants de format que j'ai utilisés dans unpack(). Pour word Je l'ai utilisé v qui signifie « non signé (toujours 16 bits, peu d'ordre d'endian) Mais pour int je l'ai utilisé l. « Long signé (toujours 32 bits, la machine octet pour) » . C'est ok sur ma machine. Mais une recherche dans la documentation du protocole pour la endianness des données.

le testdata dans $ msg a été prise à partir du résultat 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

Merci, je vais tester et revenir à vous. Merci Monsieur. –

1

J'utilise ceci:


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

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

} 

Et tout ça fonctionne bien!

+0

Je prends une route légèrement différente, mais j'approuve ce post! +1 –