PHP GatewayWorker物联网硬件解析方案

9 阅读2分钟

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' // 另一台服务器
];