引航博景做的网站网络推广是啥
背景
之前做的智慧校车/网约巴士系统(网约巴士旅游专线平台搭建历程),对接海康设备时需要对接交通部部标协议之前用的Java写的。突然想说能不能用PHP实现呢。说实话,肯定没有java顺手,不过也不是不可以,就是有点蹩脚!
以下是一个基于PHP实现JT808协议的简化示例代码,包含基础协议解析和封装逻辑:
<?php
class JT808Protocol {// 消息ID定义const MSG_ID_REGISTER = 0x0100; // 终端注册const MSG_ID_REGISTER_RESP = 0x8100; // 注册响应const MSG_ID_LOCATION = 0x0200; // 位置汇报// 协议版本const PROTOCOL_VERSION = 0x01;/*** 打包消息*/public static function packMessage($msgId, $terminalId, $msgBody, $isSubPackage = false, $encryptType = 0) {// 消息头组装$header = self::packHeader($msgId, $terminalId, strlen($msgBody), $isSubPackage, $encryptType);// 合并头和消息体$message = $header . $msgBody;// 计算校验码$checkCode = self::calculateCheckCode($message);// 添加转义字符(示例简化处理)return "\x7e" . $message . $checkCode . "\x7e";}/*** 解包消息*/public static function unpackMessage($data) {// 去除首尾的0x7e$data = substr($data, 1, -1);// 分割头和消息体$header = substr($data, 0, 16); // 头部固定16字节$msgBody = substr($data, 16, -1); // 去掉校验码// 解析头信息$headerInfo = self::unpackHeader($header);return ['header' => $headerInfo,'body' => self::unpackBody($msgBody, $headerInfo['msg_id'])];}// 私有方法:打包消息头private static function packHeader($msgId, $terminalId, $bodyLen, $isSubPackage, $encryptType) {$msgProps = ($bodyLen & 0x3FFF) | ($encryptType << 10) | ($isSubPackage ? 0x2000 : 0);return pack('nnH12nn',$msgId, // 消息ID$msgProps, // 消息属性$terminalId, // 终端手机号(BCD编码)self::getSerialNum(), // 消息流水号$bodyLen // 包总数(示例简化处理));}// 私有方法:解析消息头private static function unpackHeader($header) {$headerData = unpack('nmsg_id/nmsg_props/H12terminal_id/nserial_num/ntotal_pkgs', $header);return ['msg_id' => $headerData['msg_id'],'body_len' => $headerData['msg_props'] & 0x3FFF,'encrypt_type' => ($headerData['msg_props'] >> 10) & 0x07,'is_sub_pkg' => ($headerData['msg_props'] & 0x2000) > 0,'terminal_id' => $headerData['terminal_id'],'serial_num' => $headerData['serial_num'],'total_pkgs' => $headerData['total_pkgs']];}// 私有方法:解析消息体private static function unpackBody($body, $msgId) {switch ($msgId) {case self::MSG_ID_REGISTER:return self::unpackRegisterBody($body);case self::MSG_ID_LOCATION:return self::unpackLocationBody($body);default:return $body; // 返回原始二进制数据}}// 解析注册消息体private static function unpackRegisterBody($body) {$provinceId = unpack('n', substr($body, 0, 2))[1];$cityId = unpack('n', substr($body, 2, 2))[1];$manufacturer = substr($body, 4, 5);$model = substr($body, 9, 8);$terminalId = substr($body, 17, 7);$color = unpack('C', substr($body, 24, 1))[1];$plateNo = substr($body, 25);return ['province_id' => $provinceId,'city_id' => $cityId,'manufacturer'=> trim($manufacturer),'model' => trim($model),'terminal_id' => trim($terminalId),'color' => $color,'plate_no' => trim($plateNo)];}// 解析位置消息体private static function unpackLocationBody($body) {$data = unpack('Nalarm/Nstatus/Nlat/Nlon/nspeed/Ndirection/Ntime', $body);return ['alarm' => $data['alarm'],'status' => $data['status'],'latitude' => $data['lat'] / 1000000,'longitude' => $data['lon'] / 1000000,'speed' => $data['speed'] / 10,'direction' => $data['direction'],'time' => date('Y-m-d H:i:s', strtotime($data['time']))];}// 生成注册响应消息体public static function packRegisterResponse($serialNum, $terminalId, $resultCode) {$body = pack('nnH12', $serialNum, $resultCode, $terminalId);return self::packMessage(self::MSG_ID_REGISTER_RESP, $terminalId, $body);}// 计算校验码(异或校验)private static function calculateCheckCode($data) {$check = 0;for ($i = 0; $i < strlen($data); $i++) {$check ^= ord($data[$i]);}return pack('C', $check);}// 获取流水号(示例简单实现)private static $serialNum = 0;private static function getSerialNum() {return ++self::$serialNum % 65536;}
}// ================= 使用示例 =================
// 接收到的示例数据(16进制字符串)
$sampleData = "7e010000261234567890123456780001000178313830313233343536373839303132333435367e";// 转换二进制数据
$binaryData = hex2bin(str_replace(' ', '', $sampleData));// 解析消息
$parsedMsg = JT808Protocol::unpackMessage($binaryData);// 处理注册请求
if ($parsedMsg['header']['msg_id'] == JT808Protocol::MSG_ID_REGISTER) {// 生成响应消息$response = JT808Protocol::packRegisterResponse($parsedMsg['header']['serial_num'],$parsedMsg['header']['terminal_id'],0 // 0表示成功);// 发送响应(示例输出)echo "Response HEX: " . bin2hex($response) . "\n";
}// 打印解析结果
print_r($parsedMsg);
关键功能说明:
-
协议封装:
-
packMessage()
方法用于组装符合JT808协议的消息 -
支持消息头自动生成(包含消息ID、终端号、流水号等)
-
自动计算校验码
-
-
协议解析:
-
unpackMessage()
方法解析接收到的二进制数据 -
支持解析注册消息和位置消息
-
自动处理校验码验证
-
-
数据转换:
-
处理BCD编码的终端号
-
转换经纬度坐标(1/1000000度)
-
转换速度值(1/10 km/h)
-
-
校验处理:
-
使用异或校验算法
-
自动处理转义字符(示例简化处理)
-
典型工作流程:
-
终端发送注册消息(0x0100)
-
服务端解析后返回注册响应(0x8100)
-
终端定期发送位置信息(0x0200)
-
服务端解析位置数据并存储
扩展建议:
-
根据实际需求添加更多消息类型处理
-
完善错误处理机制
-
添加TCP粘包处理逻辑
-
实现完整的分包处理功能
-
添加数据加密支持(根据协议规范)
注意:实际使用时需要根据具体设备厂商的协议扩展进行调整,不同厂商可能会在标准协议基础上进行扩展。