PHP GatewayWorker物联网硬件解析方案
方案概述
GatewayWorker是基于Workerman开发的一个分布式长连接框架,专门用于解决TCP长连接应用开发中的常见需求。在物联网场景中,它能够高效处理设备连接、消息转发和实时通信等核心功能。
核心优势:
- 支持高并发TCP长连接,单机可维持数万连接
- 采用多进程架构,Gateway进程负责连接维持,Worker进程负责业务处理
- 内置分布式支持,可方便地扩展多台服务器
系统架构设计
1. 架构组成
本方案包含三个核心组件:
- Register服务:用于建立Gateway与Worker间的通信桥梁
- Gateway服务:负责维持设备客户端连接,处理网络IO
- Worker服务:负责业务逻辑处理,如协议解析、数据存储
2. 协议选择
物联网设备通常使用TCP协议与服务器通信,而Web端采用WebSocket协议。GatewayWorker可同时监听多种协议,并在内部实现协议转换。
核心实现代码
1. 服务端启动脚本
<?php
require_once __DIR__ . '/vendor/autoload.php';
use GatewayWorker\Gateway;
use GatewayWorker\Worker;
use GatewayWorker\Register;
// 初始化register协议
$register = new Register('text://0.0.0.0:1236');
// 初始化gateway,监听设备TCP连接
$gateway = new Gateway("tcp://0.0.0.0:8282");
$gateway->name = 'IoTGateway';
$gateway->count = 4; // 进程数
$gateway->registerAddress = '127.0.0.1:1236';
// 初始化worker,处理业务逻辑
$worker = new Worker();
$worker->name = 'IoTWorker';
$worker->count = 8; // 业务进程数
$worker->registerAddress = '127.0.0.1:1236';
// 设置业务处理类
$worker->eventHandler = 'app\\worker\\Events';
Worker::runAll();
2. 设备消息处理
<?php
namespace app\worker;
use GatewayWorker\Lib\Gateway;
class Events
{
/**
* 设备连接时触发
*/
public static function onConnect($client_id)
{
echo "设备 {$client_id} 连接成功\n";
// 记录设备连接时间
Gateway::setSession($client_id, [
'connect_time' => time(),
'device_id' => ''
]);
}
/**
* 处理设备消息
*/
public static function onMessage($client_id, $message)
{
// 解析设备数据包
$data = self::parseDevicePacket($message);
if (!$data) {
Gateway::closeClient($client_id);
return;
}
// 设备登录认证
if ($data['type'] == 'auth') {
self::deviceAuth($client_id, $data);
return;
}
// 获取设备ID
$session = Gateway::getSession($client_id);
$device_id = $session['device_id'];
// 处理心跳包
if ($data['type'] == 'heartbeat') {
Gateway::sendToClient($client_id, self::buildPacket('pong'));
return;
}
// 处理传感器数据
if ($data['type'] == 'sensor_data') {
self::saveSensorData($device_id, $data);
// 推送给订阅该设备的Web客户端
Gateway::sendToAll(json_encode([
'type' => 'sensor_update',
'device_id' => $device_id,
'data' => $data
]));
}
}
/**
* 设备认证
*/
private static function deviceAuth($client_id, $data)
{
// 验证设备ID和密钥
$device_id = $data['device_id'];
$token = $data['token'];
if (self::checkAuth($device_id, $token)) {
// 绑定设备ID到client_id
Gateway::bindUid($client_id, $device_id);
Gateway::setSession($client_id, [
'device_id' => $device_id,
'auth_time' => time()
]);
Gateway::sendToClient($client_id, self::buildPacket('auth_success'));
} else {
Gateway::sendToClient($client_id, self::buildPacket('auth_fail'));
Gateway::closeClient($client_id);
}
}
/**
* 解析设备数据包
*/
private static function parseDevicePacket($packet)
{
// 物联网设备常用数据包格式:包头(2B) + 包长度(2B) + 设备ID(6B) + 命令类型(1B) + 数据(NB) + 校验(2B)
if (strlen($packet) < 13) {
return false;
}
$header = substr($packet, 0, 2);
if ($header !== '\xAA\xAA') {
return false;
}
$length = unpack('n', substr($packet, 2, 2))[1];
$device_id = bin2hex(substr($packet, 4, 6));
$cmd_type = ord(substr($packet, 10, 1));
$content = substr($packet, 11, $length - 13);
$checksum = unpack('n', substr($packet, -2))[1];
// 校验 checksum...
return [
'device_id' => $device_id,
'type' => $cmd_type,
'data' => $content
];
}
/**
* 构建响应包
*/
private static function buildPacket($type, $data = '')
{
$response = [
'type' => $type,
'timestamp' => time(),
'data' => $data
];
return json_encode($response);
}
}
3. Web端消息推送
<?php
/**
* 向Web客户端推送设备状态
*/
class DeviceService
{
/**
* 推送设备实时数据
*/
public static function pushDeviceData($device_id, $sensor_data)
{
// 检查设备对应的Web客户端是否在线
if (Gateway::isUidOnline($device_id)) {
$message = [
'type' => 'device_update',
'device_id' => $device_id,
'data' => $sensor_data,
'time' => date('Y-m-d H:i:s')
];
Gateway::sendToUid($device_id, json_encode($message));
}
}
/**
* 控制设备
*/
public static function sendControlCommand($device_id, $command)
{
// 查找设备连接的client_id
$client_id = Gateway::getClientIdByUid($device_id);
if ($client_id) {
$packet = self::buildControlPacket($command);
Gateway::sendToClient($client_id, $packet);
return true;
}
return false;
}
}
部署与优化建议
1. 性能优化配置
// 网关配置优化
$gateway->pingInterval = 30; // 30秒心跳间隔
$gateway->pingData = '{"type":"ping"}'; // 心跳数据
$gateway->pingNotResponseLimit = 2; // 允许丢失的心跳包数量
// 设置进程间通信端口
$gateway->lanIp = '内网IP';
$gateway->startPort = 2900;
2. 分布式部署
对于大规模物联网应用,可采用多服务器部署:
// 服务器1 gateway配置
$gateway->lanIp = '192.168.1.10';
$gateway->registerAddress = [
'192.168.1.10:1236',
'192.168.1.11:1236' // 另一台服务器
];