我想知道如何通过php的unpack函数读取结构中的结构。当我得到一个IS_MCI数据包时,我检查它的类型以确保它等于ISP_MCI,然后检查NumC以找出该数据包中有多少个CompCar结构。问题是尝试通过单个函数将这些内容解压缩到一个数组中。我总是得到一个未定义的偏移量。所以,我正在寻找一些新的眼睛。
你会如何处理这个数据包?
有问题的结构是:
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)
};
答案 0 :(得分:3)
$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
)
)
)
现在,该代码做了一些您可能不想理所当然的假设(即添加更多错误/读取数据处理)。
Size
必须介于0 ... 228之间,NumC必须介于0 ... 8之间,并且两个值必须合在一起,依此类推。 word
,我使用了v
代表“无符号短(始终为16位,小端字节顺序)。但对于int
我使用过l
:“签名长(总是32位,机器字节顺序)”。我的机器上没问题。但是搜索协议文档中endianness的数据$ msg中的testdata取自
的结果__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;
}
答案 1 :(得分:1)
我正在使用它:
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;
}
}
一切正常!