Workman实现多协议控制设备的两种方案
需求简述
微信小程序控制“合宙Air724UG”模块发送指令。
可能遇到的问题
微信小程序必须使用wss://协议连接websocket;
硬件设备使用tcp协议,小程序使用websocket协议,多协议互通是个要解决的问题;
多协议之间的设备信息交互问题;
解决方案
使用Nginx反向代理做wss://实现
目前有两种方案:
一个是只搭建tcp协议,微信小程序跑服务端http接口,然后将服务端当做客户端使用tcp协议连接webscoket并传输数据。
搭建websocket并在这个进程上开一个tcp协议(推荐此方法),微信小程序使用wss协议连接websocket服务
3. 两个方案设备信息数据交互基本都是定义一个global变量在里面传递(需要注意的是,进程必须是1个,否则传递会有问题)
代码示例Demo
首先是直接搭建一个tcp协议的websocket
$address = '0.0.0.0'; $port = 39210; $ws_worker = new Worker("tcp://" . $address . ":" . $port); // 进程数必须是1 $ws_worker->count = 1; // 当收到客户端发来的数据后返回hello $data给客户端 $ws_worker->onMessage = function ($connection, $data) { // 通过全局变量获得db实例 $resultData = json_decode($data, true); if (isset($resultData['imei']) && isset($resultData['iccid'])) { // 设备进入 $this->device[$resultData['imei']] = $connection; // 设备列表,用于后续发送数据 } else { // 用户进入准备设备控制流程 if (isset($resultData['id']) && isset($resultData['command']) && isset($this->device[$resultData['id']])) { // 设备发送指令 $sendServer = $this->device[$resultData['id']]; $msg = $sendServer->send($resultData['command'] . "\r\n"); if ($msg) { $connection->send(json_encode(['code' => 1, 'msg' => '发送成功', 'data' => $resultData])); } else { $connection->send(json_encode(['code' => 0, 'msg' => '消息发送失败', 'data' => $resultData])); } } if (isset($resultData['id']) && isset($resultData['command']) && !isset($this->device[$resultData['id']])) { // 未找到对应设备 $connection->send(json_encode(['code' => 0, 'msg' => '系统繁忙,请稍后再试', 'data' => ['num' => count($this->device)]])); } } }; // Emitted when connection closed $ws_worker->onClose = function ($connection) { // echo "Connection closed\n"; }; // 运行worker Worker::runAll();
服务端提供接口发送tcp数据实现设备控制
$st = [ 'id' => 1111, // 设备识别码 'command' => '1212', // 发送的指令 ]; $st = json_encode($st); $length = strlen($st); //创建tcp套接字 $socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP); //连接tcp socket_connect($socket, '你的ip', 39210); //向打开的套集字写入数据(发送数据) $s = socket_write($socket, $st, $length); //从套接字中获取服务器发送来的数据 $msg = socket_read($socket, 8190); $result = $msg; //关闭连接 socket_close($socket); return json_decode($result, true);
到此为止了,就是这么简单,多设备调试下即可使用。好处就是微信小程序不需要配置wss
多协议websocket实现
global $ws_worker; // websocket 协议的worker $ws_worker = new Worker('Websocket://0.0.0.0:39211'); // 这里只能写1 $ws_worker->count = 1; $ws_worker->d = []; // websocket server 启动后在当前进程增加一个socket监听 $ws_worker->onWorkerStart = function ($ws_worker) { $socket_worker = new Worker('tcp://0.0.0.0:39210'); // 当设备发来数据时如何处理 $socket_worker->onMessage = function ($connection, $data) { // 这里处理设备发来的数据 $data global $ws_worker; // 比如像这样给所有的WebSocket连接转发数据 if ($data) { $resultData = json_decode($data, true); $this->device[$resultData['imei']] = $connection; $this->deviceOnline[$resultData['imei']] = $resultData; $ws_worker->d[$resultData['imei']] = $connection; } }; $ws_worker->socketWorker = $socket_worker; // 执行监听 $socket_worker->listen(); }; // websocket协议也就是浏览器发来数据时 $ws_worker->onMessage = function ($connection, $data) { global $ws_worker; if (!$data) { $connection->send(json_encode(['code' => 0, 'msg' => '无发送内容', 'data' => []])); } else { $resultData = json_decode($data, true); if (isset($resultData['id']) && isset($resultData['command']) && isset($ws_worker->d[$resultData['id']])) { // 设备发送指令 $sendServer = $ws_worker->d[$resultData['id']]; $msg = $sendServer->send($resultData['command'] . "\r\n"); if ($msg) { $connection->send(json_encode(['code' => 1, 'msg' => '发送成功', 'data' => $resultData])); } else { $connection->send(json_encode(['code' => 0, 'msg' => '消息发送失败', 'data' => $resultData])); } } if (isset($resultData['id']) && isset($resultData['command']) && !isset($ws_worker->d[$resultData['id']])) { // 未找到对应设备 $connection->send(json_encode(['code' => 0, 'msg' => '设备离线', 'data' => []])); } } }; Worker::runAll();
这样的话执行 php ws_start start -d 监听服务后,小程序端发送的数据格式就是json即可,比如
{id:111,command:222}
接下来配置下Nginx转发wss:
#SSL-END #wss协议转发 小程序里面要访问的链接 # 访问:wss://xxxx.com/wss location /wss { proxy_pass http://127.0.0.1:39211; proxy_set_header X-Real-IP $remote_addr; proxy_set_header Host $host; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; rewrite /wss/(.*) /$1 break; proxy_redirect off; }
没有更多要说的了。
评论