在 PHP 中将 UDP 数据包数据转换为人类可读的形式


Translate UDP packet data into human-readable form in PHP

我在PHP中通过UDP接收数据。在 PHP 中通过 bin2hex 函数传递缓冲区后,我最终得到类似于 Raw Data 的东西,如下例所示

这是我的PHP代码:

$socket = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP);
socket_bind($socket, "0.0.0.0" , 20500);
$from = '';
$port = 0;
socket_recvfrom($socket, $buf, 512, 0, $from, $port);
$file = 'testudp.txt';
// Open the file to get existing content
$current = file_get_contents($file);
// Append a new log line(s) to file
$current .= "New Connection " . date('Y-m-d H:i:s') . " 'n" . bin2hex($buf) . "'n";
// Write the contents back to the file
file_put_contents($file, $current);
echo "Received connection from remote address $from and remote port $port" . PHP_EOL;

这会导致类似83 05 01 02 03 04 05 01 01 01 02 00 01 4F B4 64 88 4F B4 64 88 13 BF 71 A8 BA 18 A5 06 00 00 1333 00 00 00 00 11 11 02 ...但没有空间。

数据示例及其转换为的内容:请注意,转换仅在前 9 个字节之后开始,然后是地址 2,然后再次跳过 2。

Raw Data:
 83 05 01 02 03 04 05 01 01 01 02 00 01 4F B4 64 88 4F B4 64
 88 13 BF 71 A8 BA 18 A5 06 00 00 1333 00 00 00 00 11 11 02 
 33 44 44 55 55 66 77 88 99 10 11 ?? 00 ?? 
Decoded:
  -------Message Header--------
  01           Service Type, for this message 1 = Acknowledged Request
  02           Message Type, for this message 2 = Event Report
  -------Event Report----------
  4FB46488     Update Time (5/17/12 @ 2:38pm)
  4FB46488     Time of Fix (5/17/12 @ 2:38pm)
  13BF71A8     Latitude (33.1313576)
  BA18A506     Longitude (-117.2790010)
  00001333     Altitude
  00000000     Speed
  1111         Heading
  02           Satellites
  33           Fix Status
  4444         Carrier
  5555         RSSI
  66           Comm State
  77           HDOP
  88           Inputs
  99           Unit Status
  10           Event Index
  11           Event Code
  ??           Accums (# of 4-byte Accum List values)
  00           Spare
  ??           Accum List (Varies depending on the # of Accums reporting)

我已经尝试了各种十六进制到 ascii 的解码器,我也尝试过 PHP 中的 unpack() 都无济于事。
如何通过 PHP 将数据转换为类似于示例的内容?即BA18A506最终如何以人类可读的形式为我提供数据(未格式化或非格式化)以对应于Longitude (-117.2790010)

编辑:文档指定Note that all bytes in multi-byte fields are transmitted in Net Endian format (Big Endian) where the most significant bits are transmitted first. For example, for a 32-bit field, bits 31-24 are transmitted first, 16-23 second, 8-15 third and 0-7 last如果这有帮助的话。

二进制

数据的 substr() 的 unpack() 或 unpack() 最终应该会让你到达你想要的地方。但正如 HamZa 提到的,你必须知道它是什么格式......

$test = "'x06'xA5'x18'xBA";
var_dump(unpack('l',$test));

结果:

-1172790010

只需在正确的位置添加 .

解压缩第一部分的示例代码(在需要时扩展/更正)

将代码更改为接收到缓冲区而不是文件中: socket_recv($socket, $buf, 512, 0);

然后您可以使用缓冲区$buf(现在我输入您提供的示例数据)

// Now we use some test data
$buf = "'x83'x05'x01'x02'x03'x04'x05'x01'x01'x01'x02'x00'x01'x4F'xB4'x64'x88'x4F'xB4'x64'x88'x13'xBF'x71'xA8'xBA'x18'xA5'x06'x00'x00'x13'x33'x00'x00'x00'x00'x11'x11'x02'x33'x44'x44'x55'x55'x66'x77'x88'x99'x10'x11";
// field definition
$fields = array();
$fields['header'] = array(9, 'c*');
$fields['serviceType'] = array(1, 'c');
$fields['messageType'] = array(1, 'c');
$fields['skip'] = array(2, 'c');
$fields['updateTime'] = array(4, 'l');
$fields['fixTime'] = array(4, 'l');
$fields['longitude'] = array(4, 'l');
$fields['latitude'] = array(4, 'l');
$fields['altitude'] = array(4, 'l');
$fields['speed'] = array(4, 'l');
// etc.
$values = array();
$start = 0;
foreach($fields as $type=>$setting) {
    list($len, $format) = $setting;
    $values[$type] = unpack($format, strrev(substr($buf, $start, $len)));
    $start += $len;
}
var_dump($values);

将输出如下内容:

["serviceType"]=>
array(1) {
  [1]=>
  int(1)
}
["messageType"]=>
array(1) {
  [1]=>
  int(2)
}
["skip"]=>
array(1) {
  [1]=>
  int(1)
}
["updateTime"]=>
array(1) {
  [1]=>
  int(1337222280)
}
["fixTime"]=>
array(1) {
  [1]=>
  int(1337222280)
}
["longitude"]=>
array(1) {
  [1]=>
  int(331313576)
}
["latitude"]=>
array(1) {
  [1]=>
  int(-1172790010)
}
["altitude"]=>
array(1) {
  [1]=>
  int(4915)
}
["speed"]=>
array(1) {
  [1]=>
  int(0)
}

只需将纬度和经度除以 10000000 (10M) 即可得到真实的经度和纬度