基础文档:[Workerman · ThinkPHP5.0完全开发手册 · 看云](https://www.kancloud.cn/manual/thinkphp5/235128 "Workerman · ThinkPHP5.0完全开发手册 · 看云")
在线测试地址:[EasySwoole-WebSocket在线测试工具](http://www.easyswoole.com/wstool.html "EasySwoole-WebSocket在线测试工具")
一、安装扩展包 composer require topthink/think-worker
遇到报错:不能安装,参考:[tp5 workerman安装不上解决方法 - 知乎](https://zhuanlan.zhihu.com/p/127921818 "tp5 workerman安装不上解决方法 - 知乎")
直接执行:composer require topthink/think-worker=1.0.\* 即可成功
二、新建 server.php
~~~php
#!/usr/bin/env php
<?php
define('APP_PATH', __DIR__ . '/application/');
define('BIND_MODULE','push/Worker');
// 加载框架引导文件
require __DIR__ . '/thinkphp/start.php';
~~~
![](data:image/gif;base64,R0lGODlhAQABAPABAP///wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw== "点击并拖拽以移动")
三、新建Worker.php php think make:controller push/Worker 即可,将里面的内容替换如下所示:
~~~php
<?php
namespace app\push\controller;
use think\Controller;
use think\Request;
use think\worker\Server;
use think\Cache;
class Worker extends Server
{
protected $socket = 'websocket://0.0.0.0:2346';
protected $processes = 1;
protected $uidConnections = array();
static $count = 0;
/**
* 收到信息
* @param $connection
* @param $data
*/
public function onMessage($connection, $data)
{
$retdata=json_decode($data,true);
$uid=$retdata['id'];
$message=$retdata['msg'];
if(isset($this->uidConnections[$uid]))
{
$connection = $this->uidConnections[$uid];
$connection->send($message);
// return true;
}
$connection->send('我收到你的信息了333='.$retdata['msg']);
}
/**
* 当连接建立时触发的回调函数
* @param $connection
*/
public function onConnect($connection)
{
$this->uidConnections[$connection->id] = $connection;
$connection->send('你连接了我='.$connection->id);
}
// 针对uid推送数据
public function sendMessageByUid($uid, $message)
{
if(isset($this->uidConnections[$uid]))
{
$connection = $this->uidConnections[$uid];
$connection->send($message);
return true;
}
return false;
}
/**
* 当连接断开时触发的回调函数
* @param $connection
*/
public function onClose($connection)
{
}
/**
* 当客户端的连接上发生错误时触发
* @param $connection
* @param $code
* @param $msg
*/
public function onError($connection, $code, $msg)
{
echo "error $code $msg\n";
}
/**
* 每个进程启动
* @param $worker
*/
public function onWorkerStart($worker)
{
}
}
~~~
![](data:image/gif;base64,R0lGODlhAQABAPABAP///wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw== "点击并拖拽以移动")
~~~html
四、执行 php server.php start 遇到禁用函数就去对应的PHP里面把禁用函数删除 (此命令可以放到Supervisor的守护进程里面去),并且查看端口是否运行,宝塔里面也要放行对应的端口 2346
~~~
![](data:image/gif;base64,R0lGODlhAQABAPABAP///wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw== "点击并拖拽以移动")
配置安全组参考: [回答阿里云websocket配置问题\_慕课手记](https://www.imooc.com/article/72220 "回答阿里云websocket配置问题_慕课手记") 这个很关键
测试远程连接:[http://www.voidcn.com/article/p-nifcqskk-buc.html](http://www.voidcn.com/article/p-nifcqskk-buc.html "http://www.voidcn.com/article/p-nifcqskk-buc.html") telnet localhost 2346 localhost改成外网ip即可,这个走通了,前端就能直接连接了
linux 退出Telnet命令 先输入命令:CTRL+\]然后再输入命令:quit
五、前端代码
~~~html
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Title</title>
</head>
<body>
<script>
ws = new WebSocket("ws://118.**.***.207:2346");
ws.onopen = function() {
console.log("连接成功");
ws.send('tom');
console.log("给服务端发送一个字符串:tom");
};
ws.onmessage = function(e) {
console.log("收到服务端的消息:" + e.data);
};
</script>
</body>
</html>
~~~
![](data:image/gif;base64,R0lGODlhAQABAPABAP///wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw== "点击并拖拽以移动")
# l
六、前端开两个端口即可进行相互通讯:
~~~javascript
ws.send('{"id":"2","msg":"21111111111110"}');
~~~
![](data:image/gif;base64,R0lGODlhAQABAPABAP///wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw== "点击并拖拽以移动")
最终效果如下所示:
![](https://img-blog.csdnimg.cn/20201119134210179.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM0MDUwMzYw,size_16,color_FFFFFF,t_70)![](data:image/gif;base64,R0lGODlhAQABAPABAP///wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw== "点击并拖拽以移动")编辑![](https://img-blog.csdnimg.cn/20201119134223133.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM0MDUwMzYw,size_16,color_FFFFFF,t_70)![](data:image/gif;base64,R0lGODlhAQABAPABAP///wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw== "点击并拖拽以移动")编辑
重点在这:因为在这里需要用到服务端给客户端推送,用到了text服务
## WorkerMan中php后端及时推送消息给客户端
参考连接:[WorkerMan中php后端及时推送消息给客户端-Workerman-PHP中文网](https://www.php.cn/workerman/442367.html "WorkerMan中php后端及时推送消息给客户端-Workerman-PHP中文网")
php后端及时推送消息给客户端
原理:
1、建立一个websocket Worker,用来维持客户端长连接
2、websocket Worker内部建立一个text Worker
3、websocket Worker 与 text Worker是同一个进程,可以方便的共享客户端连接
4、某个独立的php后台系统通过text协议与text Worker通讯
5、text Worker操作websocket连接完成数据推送
代码及步骤
~~~php
push.php
<?php
use Workerman\Worker;
require_once './vendor/workerman/workerman/Autoloader.php';
// 初始化一个worker容器,监听1234端口
$worker = new Worker('websocket://0.0.0.0:1234');//
/*
* 注意这里进程数必须设置为1,否则会报端口占用错误
* (php 7可以设置进程数大于1,前提是$inner_text_worker->reusePort=true)
*/
$worker->count = 1;
// worker进程启动后创建一个text Worker以便打开一个内部通讯端口
$worker->onWorkerStart = function($worker)
{
// 开启一个内部端口,方便内部系统推送数据,Text协议格式 文本+换行符
$inner_text_worker = new Worker('text://0.0.0.0:5678');
$inner_text_worker->onMessage = function($connection, $buffer)
{
// $data数组格式,里面有uid,表示向那个uid的页面推送数据
$data = json_decode($buffer, true);
$uid = $data['uid'];
// 通过workerman,向uid的页面推送数据
$ret = sendMessageByUid($uid, $buffer);
// 返回推送结果
$connection->send($ret ? 'ok' : 'fail');
};
// $connection->send('你好,你连接我了');
// ## 执行监听 ##
$inner_text_worker->listen();
};
// 新增加一个属性,用来保存uid到connection的映射
$worker->uidConnections = array();
// 当有客户端发来消息时执行的回调函数
$worker->onMessage = function($connection, $data)
{
$data=json_decode($data,true);
$connection->send('99897');
global $worker;
// 判断当前客户端是否已经验证,既是否设置了uid
if(!isset($connection->uid))
{
// 没验证的话把第一个包当做uid(这里为了方便演示,没做真正的验证)
$connection->uid = $data['id'];
/* 保存uid到connection的映射,这样可以方便的通过uid查找connection,
* 实现针对特定uid推送数据
*/
$worker->uidConnections[$connection->uid] = $connection;
$connection->send('9980'.$data['msg']);
return;
}else{
$connection->send('998123');
}
};
// 当有客户端连接断开时
$worker->onClose = function($connection)
{
global $worker;
if(isset($connection->uid))
{
// 连接断开时删除映射
unset($worker->uidConnections[$connection->uid]);
}
};
// 向所有验证的用户推送数据
function broadcast($message)
{
global $worker;
foreach($worker->uidConnections as $connection)
{
$connection->send($message);
}
}
// 针对uid推送数据
function sendMessageByUid($uid, $message)
{
global $worker;
if(isset($worker->uidConnections[$uid]))
{
$connection = $worker->uidConnections[$uid];
$connection->send($message);
return true;
}
return false;
}
// 运行所有的worker
Worker::runAll();
启动后端服务 php push.php start -d
前端接收推送的js代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Title</title>
</head>
<body>
<script>
var ws = new WebSocket('ws://118.**.**.207:1234');
ws.onopen = function(){
var uid = 'uid1';
ws.send(uid);
console.log("给服务端发送一个字符串:"+uid);
};
ws.onmessage = function(e){
// alert(e.data);
console.log("收到服务端的消息:" + e.data);
};
</script>
</body>
</html>
后端推送消息的代码
// 建立socket连接到内部推送端口
$client = stream_socket_client('tcp://127.0.0.1:5678', $errno, $errmsg, 1);
// 推送的数据,包含uid字段,表示是给这个uid推送
$data = array('uid'=>'uid1', 'percent'=>'88%');
// 发送数据,注意5678端口是Text协议的端口,Text协议需要在数据末尾加上换行符
fwrite($client, json_encode($data)."\n");
// 读取推送结果
echo fread($client, 8192);
~~~
![](data:image/gif;base64,R0lGODlhAQABAPABAP///wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw== "点击并拖拽以移动")
后端推送消息的代码和push.php监听同一个端口
push.php和前端监听同一个websocket端口
通过后端推送消息的代码向push.php推送数据,
push.php接受到数据后通过处理 利用websocket往前端推送数据
参考:
[WorkerMan中php后端及时推送消息给客户端](https://www.php.cn/workerman/442367.html "WorkerMan中php后端及时推送消息给客户端")
[workerman 内部系统推送数据](https://www.baidu.com/s?ie=utf-8&f=8&rsv_bp=1&tn=baidu&wd=workerman%20%20%E5%86%85%E9%83%A8%E7%B3%BB%E7%BB%9F%E6%8E%A8%E9%80%81%E6%95%B0%E6%8D%AE&oq=php%2520%25E8%25BF%259E%25E6%258E%25A5websocket%2520%25E5%258F%2591%25E9%2580%2581%25E6%25B6%2588%25E6%2581%25AF&rsv_pq=ad92a8a1000d2a5c&rsv_t=e510BtJ8mcMjXrby2cxwKlWpOqVkeKijK0iPv%2FBLWnxZSEO6u1pQGrcICIA&rqlang=cn&rsv_enter=1&rsv_dl=tb&rsv_btype=t&inputT=12542&rsv_sug3=97&rsv_sug1=64&rsv_sug7=100&rsv_sug2=0&rsv_sug4=13298 "workerman 内部系统推送数据")
[Centos7开放端口及查看端口](https://www.cnblogs.com/heqiuyong/p/10460150.html "Centos7开放端口及查看端口")
- 支付宝身份验证接口踩坑实录-PHP(基于ThinkPHP5)(第二版更新中)
- 抖音小程序开发之授权登录+支付宝支付+微信支付(ThinkPHP5-第三版修订中)
- TP5小知识点锦集(长期更新)
- PHP 二维码生成+识别
- 高德地图点聚合点击事件以及内容渲染
- ThinkPhP5使用phpexcle 导出数据(复制粘贴就可使用)
- Fastadmin微信小程序授权登录+获取手机号插件
- PHP -AES-128-CBC位加密解密
- PHP-Rsa分段加密解密(ThinkPHP5)
- PHP大转盘抽奖代码片段
- Fastadmin 项目上线关闭调试模式注意事项(记一次require-table.js修改事件)
- ThinkPHP5条件查询FIND_IN_SET正反使用
- ThinkPhP5整合微信小程序订阅消息
- think-queue处理延时任务事件
- ThinkPHP5 生成二维码
- Python3定时监控指定文件内容变换-(增加多行,遍历每行进行逻辑分析处理)
- Python3开发声光报警器监控触发报警
- ThinkPHP5下载文件流到本地
- 百度鹰眼抽轨迹集合稀算法&缩放比例调整显示静态图(ThinkPHP5)
- PHP 导出Excle
- Fastadmin 自定义Tab选项卡(B表的条件查询A表的数据,在A表里面加B表的参数作为选项卡)
- Fastadmin 修改url组件跳转为复制功能
- 微信H5分享好友跟朋友圈-基于Easywechat
- Python3抓取监控日志文件关键词跟内容变化修正版
- ThinkPHP5上传图片压缩处理-(解决IOS拍照上传旋转90度问题)最近更新2021年12月9日11:35:07
- 二维数组根据‘key’分组为新的三维数组
- ThinkPHP5 成功部署Workerman 运行示例
- Fastadmin框架TOKEN的使用
- ThinkPHP5 -微信小程序订阅消息开发-插件(插件基于fastadmin开发)
- ThinkPHP5-文本转义emoji表情
- ThinkPHP5 自定义命令行处理 监听Redis key失效触发回调事件,实现延迟任务 实现自动取消订单,自动完成订单
- Fastadmin插件Shopro商城里面短信插件修改为腾讯云短信插件步骤
- Fastadmin框架自定义搜索操作流程
- ThinkPHP5 处理 微信小程序内容安全审核
- Fastadmin自定义快捷搜索之模糊搜索关联他表
- php根据年月获取指定月份天数及日期数组的方法
- PHP构造函数使用校验token
- 基于ThinkPHP5&Redis腾讯云短信验证码注册登录基础业务逻辑代码整合
- ThinkPHP 解决跨域问题
- 支付宝沙箱环境测试支付(好久没做都忘了,写个博客比较省事)
- ThinkPHP5生成抖音小程序带参数二维码
- ThinkPHP5导入Excle-简单丝滑
- PHP生成带参数的小程序二维码
- ThinkPHP5成功调通IOS苹果支付
- swoole写聊天室,简单粗暴
- 微信小程序内容安全鉴别的时候,不成功因为没有转码
- Fastadmin 后台Excle文件上传(更新新增功能)
- Lnmp 配置thinkphp5 Nginx基础设置,包含http+https配置
- 通过经纬度获取数据库信息自动计算地址距离远近
- 二维数组根据某个字段排序
- PHP二维数组去重,最简单的方法
- TP5微信redis列队群发模板消息Sendmsg
- PHP检测是否关注公众号,亲测可用
- 小程序推广分享带参数二维码生成
- 基于ThinkPHP5微信H5授权登录获取用户信息(改进版)
- php过滤微信昵称中的表情
- Socket.io