2010-02-13 14 views
5

Chcę wiedzieć, jak odczytywać strukturę w strukturze za pomocą funkcji php o nazwie php: unpack. Kiedy otrzymam pakiet IS_MCI, sprawdzam jego typ, aby upewnić się, że jest równy ISP_MCI, a następnie sprawdzam NumC, aby dowiedzieć się, ile struktur CompCar znajduje się w tym pakiecie. Problem polega na rozpakowaniu tych treści do tablicy za pomocą jednej funkcji. Zawsze otrzymuję nieokreślone przesunięcie. Tak więc szukam świeżego spojrzenia na tę sprawę.Odczytywanie struktury w obrębie struktury za pomocą funkcji rozpakowywania PHP

Jak obsługiwałbyś ten pakiet?

Struct w pytanie jest takie:

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

Czy możesz opublikować funkcję, która daje nieprawidłowe przesunięcie? – Eineki

+0

To była najwyraźniej koncepcja, której nie zrozumiałem. VolkerK wyjaśnił to całkiem serio w swojej odpowiedzi. Dziękuję za patrzenie @ moje pytanie. –

Odpowiedz

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

drukuje

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 
       ) 

     ) 

) 

teraz, że kod sprawia, że ​​pewne założenia, że ​​możesz nie chcieć, aby wziąć za pewnik (czyli dodać wiele więcej błędów/odczyt danych).

  • Zakłada, że ​​pakiet ($ msg) został całkowicie odczytany przed uruchomieniem kodu. Możesz przeczytać tylko te części, które obecnie potrzebujesz (bez potrzeby substr). Bądź przynajmniej przygotowany na to, że wiadomość może dotrzeć do kilku fragmentów.
  • Przyjmuje również parametry size/num za pewnik, tzn. Nie sprawdza, czy wartości są możliwe i czy jest wystarczająca ilość danych. To zdecydowanie coś, co musicie zmienić. Size musi zawierać się między 0 ... 228, NumC musi zawierać się między 0 ... 8, a obie wartości muszą pasować do siebie i tak dalej.
  • Przyjrzyj się również identyfikatorom formatu używanym podczas rozpakowywania(). Dla word Użyłem v co oznacza „unsigned short (zawsze 16 bitów, trochę zlecenia endian bajt), ale dla int Użyłem l.«Podpisał długo (zawsze 32 bit, maszyna bajt zamówienie)» . to jest ok na moim komputerze. Ale przeszukać dokumentację protokołu dla endianness danych.

testdata w $ msg została podjęta z powodu

__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

Dziękuję, przetestuję i skontaktuję się z Tobą. Dziękuję Panu. –

1

używam to:


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

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

} 

A wszystko to działa bez zarzutu!

+0

Wybieram nieco inną trasę, ale zatwierdzam ten post! +1. –