代码之家  ›  专栏  ›  技术社区  ›  Mark Tomlin

通过PHP的解包函数读取结构中的结构

  •  6
  • Mark Tomlin  · 技术社区  · 14 年前

    我想知道如何通过php的 unpack

    你怎么处理这个包裹?

    所讨论的结构是:

    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)
    };
    
    2 回复  |  直到 14 年前
        1
  •  3
  •   VolkerK    14 年前
    $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);
    

    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位, ). 但对于 int l :“有符号长(总是32位, endianness 所有的数据。

    __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;
    }
    
        2
  •  1
  •   Misiek    14 年前

    我用这个:

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

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