fastadmin + workman 实现websocket前后端通信http

news/2025/3/6 22:56:20/文章来源:https://www.cnblogs.com/zhangyouwu/p/18756715

1.安装workman扩展

composer require workerman/workerman

2.安装think-worker

composer require topthink/think-worker=1.0.* 

3.如果在windows下使用,还需下载

composer require workerman/workerman-for-win

4.根目录创建server.php 。用来启动服务

#!/usr/bin/env php
<?php
define('APP_PATH', __DIR__ . '/application/');
define('BIND_MODULE','push/Worker');
// 加载框架引导文件
require __DIR__ . '/thinkphp/start.php';

5.新建Worker.php 服务器要记得开发端口和换域名;127.0.0.1换为0.0.0.0

1.安装workman扩展composer require workerman/workerman
2.安装think-workercomposer require topthink/think-worker=1.0.* 
3.如果在windows下使用,还需下载
composer require workerman/workerman-for-win
4.根目录创建server.php 。用来启动服务
#!/usr/bin/env php
<?php
define('APP_PATH', __DIR__ . '/application/');
define('BIND_MODULE','push/Worker');
// 加载框架引导文件
require __DIR__ . '/thinkphp/start.php';
5.新建Worker.php 服务器要记得开发端口和换域名;127.0.0.1换为0.0.0.0<?phpnamespace app\push\controller;use think\worker\Server;
use Workerman\Lib\Timer;
use think\Log;
class Worker extends Server
{protected $socket = 'websocket://127.0.0.1:2346';protected $uidConnections = [];protected $HEARTBEAT_TIME = '300';public function _initialize(){Log::init(['type' => 'File','apart_level'   =>  ['API'], 'path' =>  '../runtime/log/']);}/*** 收到信息* @param $connection* @param $data*/public function onMessage($connection, $data){// 给connection临时设置一个lastMessageTime属性,用来记录上次收到消息的时间$connection->lastMessageTime = time();$data = json_decode($data,false);//接收到消息进行逻辑处理  修改状态switch($data->type){case 'login':// 保存该用户的输送数据$this->uidConnections[$data->uid] = $connection;$connection->send('所有用户等会收到的信息');$this->send_uid($data->uid,"通过保存uid:{$data->uid}为给你发的信息");break;case 'ping':// 心跳$connection->send('pong');break;case 'sendMessage':// 发送所有消息$this->send_all($data->message,$data->uid);break;case 'sendUser' :// 发送单个消息$this->send_uid($data->uid,$data->message);break;}}/*** 当连接建立时触发的回调函数* @param $connection*/public function onConnect($connection){$connection->send('已建立连接');}/*** 当连接断开时触发的回调函数* @param $connection*/public function onClose($connection){$connection->send('连接断开');}/*** 当客户端的连接上发生错误时触发* @param $connection* @param $code* @param $msg*/public function onError($connection, $code, $msg){echo "error $code $msg\n";}/*** 每个进程启动* @param $worker*/public function onWorkerStart($worker){// 开启一个内部端口,方便内部系统推送数据,Text协议格式 文本+换行符$inner_text_worker = new \Workerman\Worker('Text://127.0.0.1:5678');$inner_text_worker->onMessage = function ($connection, $buffer){$buffer = json_decode($buffer,false);switch($buffer->type){case 'sendMessage' :$res = $this->send_all($buffer->message);break;case 'sendUser' :$res = $this->send_uid($buffer->uid,$buffer->message);break;default:$res = $this->send_all('1111');}$connection->send($res ? 'ok' : 'fail');};$inner_text_worker->listen();Timer::add($this->HEARTBEAT_TIME, function()use($worker){$time_now = time();foreach($worker->connections as $connection) {// 有可能该connection还没收到过消息,则lastMessageTime设置为当前时间if (empty($connection->lastMessageTime)) {$connection->lastMessageTime = $time_now;continue;}$diff_time = $time_now - $connection->lastMessageTime;$msg = '距离上次通话已经过去'.$diff_time.'';$connection->send($msg);// 上次通讯时间间隔大于心跳间隔,则认为客户端已经下线,关闭连接if ($time_now - $connection->lastMessageTime > $this->HEARTBEAT_TIME) {$connection->close();}}});}public function send_uid($uid,$message){if(isset($this->uidConnections[$uid])){// 获取之前用户的链接$conn = $this->uidConnections[$uid];//echo $uid.PHP_EOL;$conn->send($message);Log::write("消息发送给 UID $uid: $message", 'API'); // 添加调试日志return true;}Log::write("UID $uid 不存在", 'API'); // 添加调试日志return false;}public function send_all($message,$uid = ''){foreach($this->uidConnections as $conn){if(!empty($uid)){//不推送给自己if($conn != $this->uidConnections[$uid]){$conn->send($message);}}else{$conn->send($message);}}return true;}
}
Worker.php

6.根目录下执行命令,运行服务

php server.php start

7.新加test.html 用来接受测试,记得将127.0.0.1换为域名

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title><script>// 创建一个Socket实例var socket = new WebSocket('ws://127.0.0.1:2346');var uid = "33";//心跳间隔var heartbeatInterval = 290 * 1000;// 打开Socketsocket.onopen = function(event) {// 发送一个初始化消息
            socket.send(JSON.stringify({type: "login",uid: uid,}));// 启动心跳定时器
             startHeartbeat();};socket.onmessage = function(event) {console.log('收到消息',event.data);// 处理收到的心跳回复if (event.data === 'pong') {console.log('心跳回复');}};// 监听Socket的关闭socket.onclose = function(event) {console.log('关闭监听',event);// 连接关闭后,清除心跳定时器
            stopHeartbeat();};// 心跳定时器var heartbeatTimer;function startHeartbeat() {heartbeatTimer = setInterval(function() {socket.send(JSON.stringify({ type: 'ping' }));console.log('发送心跳');}, heartbeatInterval);}function stopHeartbeat() {if (heartbeatTimer) {clearInterval(heartbeatTimer);heartbeatTimer = null;}}function  send(){var val = $("#msg").val();if(val==''){alert('请输入发送内容');return false;}socket.send(JSON.stringify({type: "sendMessage",uid: uid,message:val}));}</script>
</head>
<body>
<input type="text" id="msg">
<button onclick="send()">发送消息</button>
</body>
<script src="https://code.jquery.com/jquery-3.1.1.min.js"></script>
</html>
test.html

8.手动推送消息

 public static function push_msg($str = '',$uid = '33' ){// $uid = input('uid','33');$type = input('type','sendUser');$msg = input('msg','hello word');$client = stream_socket_client('tcp://127.0.0.1:5678', $errno, $errmsg, 1);if (!$client) {echo "Error: $errmsg\n";return false;}// 推送的数据,包含用户,表示是给这个用户推送//有数据则进行推送if($str){$data = array('uid'=>$uid, 'message'=>$str,'type'=>$type);// 发送数据,注意5678端口是Text协议的端口,Text协议需要在数据末尾加上换行符$bytesWritten = fwrite($client, json_encode($data) . "\n");if ($bytesWritten === false) {Log::write('Failed to write data to the socket', 'API');fclose($client);return false;}stream_set_timeout($client, 1);// 读取推送结果$response = fread($client, 8192);fclose($client);return $response;}}
View Code

 

结果:

 

原文地址:https://blog.csdn.net/qq_43630915/article/details/140843610

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/894861.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

日报202536

继续学习了Springboot,感觉有点麻烦:User package com.xxx.demo1.pojo;public class User {String id;String name;@Overridepublic String toString() {return "User{" +"id=" + id + \ +", name=" + name + \ +};}public String getId() {re…

[JLOI2014] 路径龟划

传送门 我的部落格 貌似没有比较通俗介绍红绿灯期望介绍方法的?我来一发不需要积分基础能看懂的严谨证明~ 题目大意 这道题 luogu 题面不太清晰,大意给定一张无向图,你需要开车从起点走到终点,有些点会设红绿灯,给出每个红绿灯的红灯时间和绿灯时间,你见到红绿灯时红绿灯…

Vue 脚手架发展

Vue 脚手架是一个基于 Vue.js 进行快速开发的完整系统,Vue 脚手架致力于将 Vue 生态中的工具基础标准化。Vue 的工具链 CLI(通常指 @vue/cli)与 create-vue 是 Vue 生态中两个不同的脚手架工具,它们在功能定位、技术栈和适用场景上有显著区别。 Vue CLI(@vue/cli) Vue CL…

18C++循环结构-多重循环(1)

1、循环的嵌套; 2、双重循环的应用一、循环的嵌套 问题:#include <iostream> using namespace std; int main() {int j;for(j=1;j<=5;j++)cout<<*;return 0; }再编一程序,每次输出3行,每行5个"*"号。 在外层加一个循环语句来实现;流程图如:#inc…

Mybatis-plus01--快速开始

前言 在编写Java开发过程中,尤其是CRUD开发,我们会发现大部分事件都在编写Java持久层的增删改查上了,并且配置mybatis的mapper文件也是一件麻烦的事。如果你也有这样的烦劳,看来就可以认识一下我们的新朋友mybatis-plus了。 MyBatis-Plus 是一个 Mybatis的增强工具,在 MyB…

作业二:文本查重

作业介绍这个作业属于哪个课程 https://edu.cnblogs.com/campus/gdgy/SoftwareEngineeringClassof2023github https://github.com/Ryon-h/3123003446这个作业要求在哪里 https://edu.cnblogs.com/campus/gdgy/SoftwareEngineeringClassof2023/homework/13324这个作业的目标 完成…

上哪儿下载stable diffusion

要在本地环境中下载和安装Stable Diffusion,您可以遵循以下几种方法: 方法一:GitHub源码下载(工作流下载:https://www.mix688.com/964.html)硬件与软件环境准备:确保计算机配备至少4GB显存的NVIDIA GPU。安装Windows操作系统。准备大约10GB的硬盘空间。安装所需软件:下…

清华大学DeepSeek课程:基于DeepSeek的AI音乐词曲创作法(附视频下载)

本课程由清华大学新媒沈阳团队精心打造,旨在教授大家如何利用DeepSeek这一强大的AI工具进行音乐词曲创作。DeepSeek不仅能够帮助我们理解音乐创作的基本原理,还能激发我们的创造力。本课程由清华大学新媒沈阳团队精心打造,旨在教授大家如何利用DeepSeek这一强大的AI工具进行…

2024 年中国大学生程序设计竞赛全国邀请赛(郑州)暨第六届 CCPC 河南省大学生程序设计竞赛(Problem L. Toxel 与 PCPC II)

对于这道题我最开始是想用斜率优化dp,但是x是四次方明显不行,如果是二次方就好了,所以要换一个思路, 可以观察到如果一次性修复的x太多了,会导致时间消耗太大,这样我们还不如一个错误一个错误的修,当x=22时x的四次方就超过了200000,所以说我们最多一次修复22个bug了,值…

2025.3.3微服务架构(Dubbo)

Dubbo配置方式 1.注解: 基于注解可以快速的将程序配置,无需多余的配置信息,包含提供者和消费者。弊端是根据配置信息无法快速定位。XML:和Spring做结合,相关的Service和Reference均使用Spring集成后的。通过这样的方式可以很方便的通过几个文件进行管理整个集群配置。可以快…

数据集蒸馏论文阅读

Dataset Distillation 18年的论文,最早提出数据蒸馏的概念 理论 通常的梯度下降是小批量的 SGD,每次都需要从训练数据中选一个 minibatch 来更新。这篇文章的重点是学习到一个合成数据 \(\hat x=\{\hat x_i\}_{i=1}^M\) 和学习率 \(\hat \eta\),这样我们就可以固定梯度下降的…