当前位置: 首页 > article >正文

Thinkphp6实现websocket

项目需要连接一台自动售货机,售货机要求两边用websocket连接,监听9997端口。本文实现了一个基于PHP的WebSocket服务器,用于连接自动售货机,支持start/stop/restart命令操作

1.新建文件

新建文件 /command/socket.php

<?php
namespace app\command;use think\console\Command;
use think\console\Input;
use think\console\input\Argument;
use think\console\Output;class TestSocket extends Command
{public $server;protected static $pidFile = '/tmp/test_socket.pid';protected static $running = true;protected function configure(){$this->setName('test:socket')->setDescription('WebSocket server for JieLe')->addArgument('action', Argument::OPTIONAL, 'start|stop|restart', 'start');}protected function execute(Input $input, Output $output){$action = $input->getArgument('action');switch ($action) {case 'start':$this->startServer($output);break;case 'stop':$this->stopServer($output);break;case 'restart':$this->stopServer($output);sleep(1); // 等待1秒确保服务停止$this->startServer($output);break;default:$output->writeln("Invalid action. Use start|stop|restart");break;}}protected function startServer(Output $output){// 检查是否已运行if (file_exists(self::$pidFile)) {$pid = file_get_contents(self::$pidFile);if (posix_getpgid($pid)) {$output->writeln("Server is already running (PID: {$pid})");return;}}// 创建TCP Socket服务器$this->server = stream_socket_server("tcp://0.0.0.0:9997", $errno, $errstr);if (!$this->server) {$output->error("Failed to start server: $errstr ($errno)");return;}// 保存PIDfile_put_contents(self::$pidFile, getmypid());// 注册信号处理器pcntl_signal(SIGTERM, function() {self::$running = false;});pcntl_signal(SIGINT, function() {self::$running = false;});$output->info("WebSocket server running on ws://0.0.0.0:9997");$clients = [];while (self::$running) {// 处理信号pcntl_signal_dispatch();$read = array_merge([$this->server], $clients);$write = $except = null;// 使用stream_select监听活动连接if (stream_select($read, $write, $except, 5) > 0) {// 处理新连接if (in_array($this->server, $read)) {$client = stream_socket_accept($this->server);$clients[] = $client;}// 处理客户端消息foreach ($read as $socket) {if ($socket === $this->server) continue;$data = fread($socket, 1024);if ($data === false || $data === '') {// 客户端断开$key = array_search($socket, $clients);unset($clients[$key]);fclose($socket);continue;}// WebSocket握手处理if (strpos($data, 'Upgrade: websocket') !== false) {$this->handshake($socket, $data);continue;}// 处理WebSocket帧$decoded = $this->decodeFrame($data);//$decoded = $this->main($decoded); 实际处理业务的函数// 发送回复$response = $decoded;$frame = $this->encodeFrame($response);fwrite($socket, $frame);}}}// 清理工作foreach ($clients as $client) {fclose($client);}fclose($this->server);unlink(self::$pidFile);$output->writeln("Server stopped");}protected function stopServer(Output $output){if (!file_exists(self::$pidFile)) {$output->writeln("Server is not running");return;}$pid = file_get_contents(self::$pidFile);if (posix_getpgid($pid)) {posix_kill($pid, SIGTERM);$output->writeln("Stopping server (PID: {$pid})...");// 等待进程结束$timeout = 10; // 10秒超时while ($timeout-- > 0 && posix_getpgid($pid)) {sleep(1);}if (posix_getpgid($pid)) {posix_kill($pid, SIGKILL); // 强制杀死}}if (file_exists(self::$pidFile)) {unlink(self::$pidFile);}$output->writeln("Server stopped");}/************************************************** websocket转码相关函数  *******************************************************/// WebSocket帧解码public function decodeFrame($data){$len = ord($data[1]) & 127;if ($len === 126) {$masks = substr($data, 4, 4);$data = substr($data, 8);} elseif ($len === 127) {$masks = substr($data, 10, 4);$data = substr($data, 14);} else {$masks = substr($data, 2, 4);$data = substr($data, 6);}$decoded = '';for ($i = 0; $i < strlen($data); $i++) {$decoded .= $data[$i] ^ $masks[$i % 4];}return $decoded;}// WebSocket帧编码public function encodeFrame($data){$frame = [];$frame[0] = 0x81; // FIN + text frame$len = strlen($data);if ($len <= 125) {$frame[1] = $len;} elseif ($len <= 65535) {$frame[1] = 126;$frame[2] = ($len >> 8) & 255;$frame[3] = $len & 255;} else {$frame[1] = 127;for ($i = 0; $i < 8; $i++) {$frame[$i + 2] = ($len >> (8 * (7 - $i))) & 255;}}$frame = array_map('chr', $frame);$frame = implode('', $frame) . $data;return $frame;}// WebSocket握手处理public function handshake($socket, $headers){if (preg_match('/Sec-WebSocket-Key: (.*)\r\n/', $headers, $match)) {$key = base64_encode(sha1($match[1] . '258EAFA5-E914-47DA-95CA-C5AB0DC85B11', true));$response = "HTTP/1.1 101 Switching Protocols\r\n";$response .= "Upgrade: websocket\r\n";$response .= "Connection: Upgrade\r\n";$response .= "Sec-WebSocket-Accept: $key\r\n\r\n";fwrite($socket, $response);}}
}

2.开启服务
docker exec php7.3 php /lnmp/nginx/data/thinkphp6/think test:socket start
docker exec php7.3 php /lnmp/nginx/data/thinkphp6/think test:socket stop
docker exec php7.3 php /lnmp/nginx/data/thinkphp6/think test:socket restart
在这里插入图片描述

3.在nginx配置目录,可通过浏览器访问socket业务

server {listen 80;root 省略;#172.18.0.3是提供php服务的iplocation /rtsp {proxy_pass http://172.18.0.3:9997;proxy_http_version 1.1;proxy_set_header Upgrade $http_upgrade;proxy_set_header Connection "upgrade";proxy_set_header Host $host;proxy_read_timeout 600s;}location ~ \.php$ {#省略}}

4.测试

相关文章:

Thinkphp6实现websocket

项目需要连接一台自动售货机&#xff0c;售货机要求两边用websocket连接,监听9997端口。本文实现了一个基于PHP的WebSocket服务器&#xff0c;用于连接自动售货机&#xff0c;支持start/stop/restart命令操作 1.新建文件 新建文件 /command/socket.php <?php namespace a…...

web-css

一.CSS选择器&#xff1a; 1.基础选择器 基本选择器&#xff1a; >.标签选择器 格式&#xff1a;标签名称{} >.类选择器&#xff08;重&#xff09; 格式&#xff1a;.class属性的值{} >.id选择器 格式&#xff1a;#id属性的值{} >.通配符&#xff08;表示所有&am…...

关于 smali:2. 从 Java 到 Smali 的映射

一、对照 Java 代码与 Smali 代码差异 1.1 方法调用差异&#xff1a;Java vs Smali Java 方法分类&#xff1a; 方法类型Java 示例Smali 指令特点说明静态方法Utils.print("hi")invoke-static没有 this 指针实例方法obj.show()invoke-virtual有 this&#xff0c;虚…...

三、zookeeper 常用shell命令

作者&#xff1a;IvanCodes 日期&#xff1a;2025年5月28日 专栏&#xff1a;Zookeeper教程 ZooKeeper Shell (zkCli.sh) 是与ZooKeeper服务器交互的核心工具。本教程将详细介绍常用命令&#xff0c;并重点解析ZooKeeper数据节点 (ZNode) 的特性与分类。 思维导图 一、连接 Zo…...

分布式流处理与消息传递——Paxos Stream 算法详解

Java 实现 Paxos Stream 算法详解 一、Paxos Stream 核心设计 #mermaid-svg-cEJcmpaQwLXpEbx9 {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-cEJcmpaQwLXpEbx9 .error-icon{fill:#552222;}#mermaid-svg-cEJcmpaQw…...

智变与重构:AI 赋能基础教育教学的范式转型研究报告

一、研究背景与核心价值 &#xff08;一&#xff09;技术驱动下的教育转型浪潮 在全球数字化转型加速的背景下&#xff0c;人工智能作为核心技术力量&#xff0c;正重塑基础教育生态。据《人工智能赋能未来教育研究报告》指出&#xff0c;我国教育数字化战略行动已推动超 70…...

平衡三进制

平衡三进制 - OI Wiki https://oi-wiki.org/math/balanced-ternary/ 上海市计算机学会竞赛平台 | YACS 方法一&#xff0c;先分离后进位 #include <iostream> using namespace std; int n, a[100], cnt; bool flag; int main() {cin >> n;if(n0){cout <<…...

针对Python开发的工具推荐及分析,涵盖集成开发环境(IDE)、轻量级工具、在线开发平台、代码管理工具等)

以下是针对Python开发的工具推荐及全面分析&#xff0c;涵盖集成开发环境&#xff08;IDE&#xff09;、轻量级工具、在线开发平台、代码管理工具等&#xff0c;结合不同场景和需求进行分类说明&#xff1a; 目录 一、集成开发环境&#xff08;IDE&#xff09; 1. PyCharm 2…...

960g轻薄本,把科技塞进巧克力盒子

朋友们&#xff0c;谁懂啊 最近本打工人被同事疯狂种草了一款 “巧克力盒子” 华硕灵耀 14 Air 骁龙版&#xff01; 960g的重量比一瓶大可乐还轻 塞进通勤包毫无压力 连健身房的瑜伽垫都能多卷两圈 这台行走的生产力工具&#xff0c;到底有啥魔法&#xff1f; 今天就带…...

xcode 编译运行错误 Sandbox: rsync(29343) deny(1) file-write-create

解决方法 方法一&#xff1a;修改Targets -> Build Settings 中 ENABLE_USER_SCRIPT_SANDBOXING 设置 NO 方法二&#xff1a;项目使用cocoaPods进行三方管理 且 使用了 use_frameworks&#xff0c;把 use_frameworks 注释掉,然后重新自行pod install...

C# 基于 Windows 系统与 Visual Studio 2017 的 Messenger 消息传递机制详解:发布-订阅模式实现

&#x1f9d1; 博主简介&#xff1a;CSDN博客专家、CSDN平台优质创作者&#xff0c;高级开发工程师&#xff0c;数学专业&#xff0c;10年以上C/C, C#, Java等多种编程语言开发经验&#xff0c;拥有高级工程师证书&#xff1b;擅长C/C、C#等开发语言&#xff0c;熟悉Java常用开…...

ComfyUI+阿里Wan2.1+内网穿透技术:本地AI视频生成系统搭建实战

文章目录 前言1.软件准备1.1 ComfyUI1.2 文本编码器1.3 VAE1.4 视频生成模型 2.整合配置3. 本地运行测试4. 公网使用Wan2.1模型生成视频4.1 创建远程连接公网地址 5. 固定远程访问公网地址总结 前言 各位技术爱好者&#xff0c;今天为您带来一组创新性的AI应用方案&#xff01…...

腾讯云开发者社区文章内容提取免费API接口教程

接口简介&#xff1a; 提取指定腾讯云开发者社区文章内容。本接口仅做内容提取&#xff0c;未经作者授权请勿转载。 请求地址&#xff1a; https://cn.apihz.cn/api/caiji/tencent.php 请求方式&#xff1a; POST或GET。 请求参数&#xff1a; 【名称】【参数】【必填】【说…...

利用海外代理IP,做Twitter2026年全球趋势数据分析

近年来&#xff0c;社交媒体趋势分析逐渐成为品牌监控、市场洞察和消费者研究的必备工具。而当谈到全球趋势数据分析&#xff0c;很多人都会立即想到 Twitter趋势&#xff08;逼近连美丽国的总统都喜欢在上面发表自己的看法- -!!!&#xff09;。Twitter趋势&#xff0c;即Twitt…...

OpenLayers 图形交互编辑

注&#xff1a;当前使用的是 ol 5.3.0 版本&#xff0c;天地图使用的key请到天地图官网申请&#xff0c;并替换为自己的key 图形要素包括属性信息和几何信息&#xff0c;在实际应用中&#xff0c;不仅需要修改样式信息&#xff0c;也需要修改图形几何信息。在OpenLayers中&…...

pikachu靶场通关笔记06 XSS关卡02-反射型POST

目录 一、XSS 二、反射型XSS 三、POST型报文 四、GET型与POST型区别 五、代码审计 五、渗透实战 1、渗透方法1 2、渗透方法2 本系列为通过《pikachu靶场通关笔记》的XSS关卡(共10关&#xff09;渗透集合&#xff0c;通过对XSS关卡源码的代码审计找到XSS风险的真实原因&…...

SQLiteStudio - 免费开源、轻量高效,跨平台的 SQLite 数据库管理工具,代替 Navicat for SQLite

管理 SQLite 数据库就用这款软件&#xff0c;真的早该摒弃破解和盗版的 Navicat 了。 SQLiteStudio 是一款专注于管理 SQLite 数据库 的桌面软件&#xff0c;用于浏览和编辑 SQLite 数据库文件。软件的作者是来自波兰的开发者 Paweł Salawa&#xff0c;他是一位拥有 20 年 Ja…...

Prometheus + Grafana + Cadvisor:构建高效企业级服务监控体系

在现代软件开发和运维领域&#xff0c;容器化技术的应用越来越广泛&#xff0c;其中 Docker 作为最受欢迎的容器化解决方案之一&#xff0c;其容器的监控管理变得至关重要。本文将详细介绍如何使用 cadvisor、Prometheus 和 Grafana 来监控 Docker 容器的状态。 一、安装镜像 …...

WEBSTORM前端 —— 第3章:移动 Web —— 第2节:空间转换、转化

目录 一、空间转换 1.空间转换 2.空间转换 – 平移 3.视距 perspective 4.空间 – 旋转 ③空间旋转——Z轴代码与效果视频 ④空间旋转——X轴代码与效果视频 ⑤空间旋转——Y轴代码与效果视频 5.立体呈现 – transform-style 案例 – 3D 导航 6.空间转换 – 缩放 …...

Java研学-MongoDB(一)

一 MongoDB 简介 MongoDB是一种高性能、开源的NoSQL数据库&#xff0c;采用面向文档的存储模型&#xff0c;以BSON&#xff08;Binary JSON&#xff09;格式存储数据&#xff0c;具有灵活的数据模型、强大的扩展性和丰富的功能特性&#xff0c;广泛应用于各类现代应用程序的数据…...

【AI面试秘籍】| 第25期:RAG的关键痛点及解决方案深度解析

今天我们来聊聊大模型领域一个非常火热的技术——RAG&#xff08;Retrieval Augmented Generation&#xff09;。RAG通过引入外部知识库&#xff0c;有效地缓解了大型语言模型&#xff08;LLM&#xff09;在处理知识密集型任务时可能出现的幻觉、知识过时等问题。然而&#xff…...

OpenGL、GLUT、freeGLUT 与 GLFW 的区别

在图形编程中&#xff0c;OpenGL 是最核心的渲染 API&#xff0c;但仅靠它本身无法完成窗口创建、事件处理等任务。因此&#xff0c;开发者通常会借助一些辅助库来简化开发流程。常见的库包括 GLUT、freeGLUT 和 GLFW。 本文将详细讲解这些技术之间的区别&#xff0c;并提供每…...

服务器带宽线路的区别(GIA、CN2、BGP、CMI等)

服务器带宽线路的区别&#xff08;GIA、CN2、BGP、CMI等&#xff09; 一、BGP线路 1. 定义与技术特点 BGP&#xff08;Border Gateway Protocol&#xff0c;边界网关协议&#xff09;是一种用于不同自治系统&#xff08;AS&#xff09;之间交换路由信息的协议&#xff0c;属…...

ppt一键制作:ai自动生成PPT,便捷高效超级精美!

深夜的台灯下&#xff0c;你对着杂乱的 PPT 内容反复刷新灵感&#xff0c;鼠标在字体、配色选项间来回穿梭&#xff0c;好不容易拼凑出的页面&#xff0c;却总透着浓浓的 “廉价感”&#xff1b;汇报在即&#xff0c;逻辑混乱的大纲改了又改&#xff0c;每一页感觉合适又不搭&a…...

多方法解决MNIST数字识别

全连接层 import torch from torchvision import datasets, transforms import torch.nn as nn import torch.optim as optim from tqdm import tqdm # 用于进度条显示 import os# 定义数据预处理(标准化+Tensor转换) transform = transforms.Compose([transforms.ToTensor…...

Maven(黑马)

Maven 是一个强大的项目管理和构建自动化工具&#xff0c;主要用于 Java 项目的构建、依赖管理和文档生成。它通过使用 POM&#xff08;Project Object Model&#xff09;文件来管理项目的配置和依赖关系&#xff0c;从而实现项目的自动化构建和管理。以下是 Maven 的一些核心概…...

CppCon 2014 学习:ODB, Advanced Weapons and Tactics

#Schema Evolution 是数据库持久化技术中的一个重要概念&#xff0c;特别是在使用像 ODB 这样的 C ORM 框架时。 展示的代码片段正是 ODB 支持的**模式演化&#xff08;Schema Evolution&#xff09;**语法示例。 什么是 Schema Evolution&#xff1f; Schema Evolution 指的…...

将手机网络经USB数据线和本地局域网共享给华为AP6050DN无线接入点

引言 由于最近装毕的新家所在的小区未能及时通宽带,于是家中各类无线设备如何上网就成了首要要解决的问题。 鉴于家中要联网的设备多、类型杂、支持频段也不一,总是开手机热点不是回事儿,于是就想着把手机网络引至华为AP6050DN无线接入点中,让家中所有的无线设备都能快速高…...

【论文解读】Deformable DETR | Deformable Transformers for End-to-End Object Detection

论文地址&#xff1a;https://arxiv.org/pdf/2010.04159 代码地址&#xff1a;https://github.com/fundamentalvision/Deformable-DETR 摘要 DETR最近被提出&#xff0c;旨在消除物体检测中许多手工设计的组件的需求&#xff0c;同时展示出良好的性能。然而&#xff0c;由于T…...

android 图片背景毛玻璃效果实现

图片背景毛玻璃效果实现 1 依赖 // Glide implementation("com.github.bumptech.glide:glide:4.16.0") kapt("com.github.bumptech.glide:compiler:4.16.0") implementation("jp.wasabeef:glide-transformations:4.3.0") 2 布局<com.googl…...