2

我在 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 是否有帮助。

4

1 回答 1

2

二进制数据的每个 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)即可得到真正的经纬度

于 2013-10-25T14:13:12.350 回答