首先通过 composer 安装 workerman
根项目下安装
composer require topthink/think-worker
安装的文件地址
配置文件多出的 worker.php 和 worker_server.php
方法1
worker.php文件
<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006-2018 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: liu21st <liu21st@gmail.com>
// +----------------------------------------------------------------------
// +----------------------------------------------------------------------
// | Workerman设置 仅对 php think worker 指令有效
// +----------------------------------------------------------------------
return [
// 扩展自身需要的配置
'host' => '0.0.0.0', // 监听地址,0.0.0.0外网内网都可以访问,也可以指定
'port' => 9527, // 监听端口
'root' => '', // WEB 根目录 默认会定位public目录
'app_path' => '', // 应用目录 守护进程模式必须设置(绝对路径)
'file_monitor' => false, // 是否开启PHP文件更改监控(调试模式下自动开启)
'file_monitor_interval' => 2, // 文件监控检测时间间隔(秒)
'file_monitor_path' => [], // 文件监控目录 默认监控application和config目录
// 支持workerman的所有配置参数
'name' => 'thinkphp',
'count' => 4,
'daemonize' => false,
'pidFile' => '',
];
worker_server.php文件
<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006-2018 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: liu21st <liu21st@gmail.com>
// +----------------------------------------------------------------------
// +----------------------------------------------------------------------
// | Workerman设置 仅对 php think worker:server 指令有效
// +----------------------------------------------------------------------
return [
// 扩展自身需要的配置
'protocol' => 'websocket', // 协议 支持 tcp udp unix http websocket text
'host' => '0.0.0.0', // 监听地址,0.0.0.0外网内网都可以访问,也可以指定
'port' => 9527, // 监听端口
'socket' => '', // 完整监听地址
'context' => [], // socket 上下文选项
'worker_class' => '', // 自定义Workerman服务类名 支持数组定义多个服务
// 支持workerman的所有配置参数
'name' => 'thinkphp',
'count' => 4,
'daemonize' => false,
'pidFile' => '',
// 支持事件回调
// onWorkerStart
'onWorkerStart' => function ($worker) {
},
// onWorkerReload
'onWorkerReload' => function ($worker) {
},
// onConnect
'onConnect' => function ($connection) {
},
// onMessage
'onMessage' => function ($connection, $data) {
$connection->send('receive success 123');
},
// onClose
'onClose' => function ($connection) {
},
// onError
'onError' => function ($connection, $code, $msg) {
echo "error [ $code ] $msg\n";
},
];
方法2推荐
上面的两个文件可以不用理,我们自定一个Worker类
worker_server.php文件 worker_class地方加上Worker.php位置
'worker_class' => 'Worker.php位置',位置错了会报错找不到文件
<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006-2018 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: liu21st <liu21st@gmail.com>
// +----------------------------------------------------------------------
// +----------------------------------------------------------------------
// | Workerman设置 仅对 php think worker:server 指令有效
// +----------------------------------------------------------------------
return [
// 扩展自身需要的配置
'protocol' => 'websocket', // 协议 支持 tcp udp unix http websocket text
'host' => '0.0.0.0', // 监听地址
'port' => 9527, // 监听端口
'socket' => '', // 完整监听地址
'context' => [], // socket 上下文选项
'worker_class' => 'app\controller\Index\Worker', // 自定义Workerman服务类名 支持数组定义多个服务
// 支持workerman的所有配置参数
'name' => 'thinkphp',
'count' => 4,
'daemonize' => false,
'pidFile' => '',
// 支持事件回调
// onWorkerStart
'onWorkerStart' => function ($worker) {
},
// onWorkerReload
'onWorkerReload' => function ($worker) {
},
// onConnect
'onConnect' => function ($connection) {
},
// onMessage
'onMessage' => function ($connection, $data) {
$connection->send('receive success 123');
},
// onClose
'onClose' => function ($connection) {
},
// onError
'onError' => function ($connection, $code, $msg) {
echo "error [ $code ] $msg\n";
},
];
创建好之后
Worker.php代码
<?php
namespace app\controller\Index;
use think\worker\Server;
use Workerman\Lib\Timer;
class Worker extends Server{
protected $socket = 'websocket://0.0.0.0:9527';
/**
* 收到信息
* @param $connection
* @param $data
*/
public function onMessage($connection, $data)
{
echo '后台收到前台的信息';
echo $data;
$connection->send('我收到你的信息了,后台收到前台的信息了');
}
/**
* 当连接建立时触发的回调函数
* @param $connection
*/
public function onConnect($connection)
{
}
/**
* 当连接断开时触发的回调函数
* @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)
{
}
}
试着启动下服务
php think worker:server
如下图,表示启动正常
如果出现错误,先查看下端口是否已放行
如果是php环境是第一次安装,有些对应的禁用函数需要删除,启动时会提示哪些函数被禁用了
vue,uniapp也是同理
websocet.js封装好了类
let isSocketClose = false; // 是否关闭socket
let reconnectCount = 5; // 重连次数
let heartbeatInterval = "50"; // 心跳定时器
let socketTask = null; // websocket对象
let againTimer = null; //断线重连定时器
let url = null;
let onReFn = null;
let onSucFn = null;
let onErrFn = null;
/**
* sockeUrl:websocet的地址
* onReceive:消息监听的回调
* onErrorEvent:抛出错误的回调,且弹窗连接失败的提示框
* onErrorSucceed:抛出成功回调,主要用于隐藏连接失败的提示框
* */
const sokcet = (sockeUrl, onReceive, onErrorEvent, onErrorSucceed) => {
url = sockeUrl;
onReFn = onReceive;
onErrFn = onErrorEvent;
onSucFn = onErrorSucceed;
isSocketClose = false;
//判断是否有websocet对象,有的话清空
if (socketTask) {
socketTask.close();
socketTask = null;
clearInterval(heartbeatInterval);
}
//WebSocket的地址
// 【非常重要】必须确保你的服务器是成功的,如果是手机测试千万别使用ws://127.0.0.1:9099【特别容易犯的错误】
let url = sockeUrl
// 连接
socketTask = uni.connectSocket({
url: url,
success(data) {
console.log("websocket连接成功");
clearInterval(againTimer) //断线重连定时器
},
fail: (err) => {
console.log("报错", err);
}
});
// 连接打开
socketTask.onOpen((res) => {
console.log('WebSocket打开');
clearInterval(againTimer) //断线重连定时器
onErrorSucceed({
isShow: false
}) // 用于提示框的隐藏
heartbeatInterval && clearInterval(heartbeatInterval);
// 10秒发送一次心跳
heartbeatInterval = setInterval(() => {
sendMsg('心跳ing')
}, 1000 * 5)
})
// 监听连接失败
socketTask.onError((err) => {
console.log('WebSocket连接打开失败,请检查', err);
//停止发送心跳
clearInterval(heartbeatInterval)
//如果不是人为关闭的话,进行重连
if (!isSocketClose) {
reconnect(url, onErrorEvent)
}
})
// // 监听连接关闭 -
socketTask.onClose((e) => {
console.log('WebSocket连接关闭!');
clearInterval(heartbeatInterval)
if (!isSocketClose) {
reconnect(url, onErrorEvent)
}
})
// 监听收到信息
socketTask.onMessage((res) => {
uni.hideLoading()
console.log(res, 'res监听收到信息')
let serverData = res.data
//与后端规定好返回值分别代表什么,写业务逻辑
serverData && onReceive(serverData);
});
}
const reconnect = (url, onErrorEvent) => {
console.log('进入断线重连', isSocketClose);
clearInterval(againTimer) //断线重连定时器
clearInterval(heartbeatInterval);
socketTask && socketTask.close(); // 确保已经关闭后再重新打开
socketTask = null;
onErrorEvent({
isShow: true,
messge: '扫描头服务正在连接...'
})
// 连接 重新调用创建websocet方法
againTimer = setInterval(() => {
sokcet(url, onReFn, onErrFn, onSucFn)
console.log('在重新连接中...');
}, 1000 * 5)
}
const sendMsg = (msg) => { //向后端发送命令
msg = JSON.stringify(msg)
try {
//通过 WebSocket 连接发送数据
socketTask.send({
data: msg
});
} catch (e) {
if (isSocketClose) {
return
} else {
reconnect(url, onErrFn)
}
}
}
// 关闭websocket【必须在实例销毁之前关闭,否则会是underfined错误】beforeDestroy() {websocetObj.stop();}
const stop = () => {
isSocketClose = true
clearInterval(heartbeatInterval);
clearInterval(againTimer) //断线重连定时器
socketTask.close(); // 确保已经关闭后再重新打开
socketTask = null;
}
export const websocetObj = {
sokcet,
stop,
sendMsg
};
需要引用的页面
<script>
import {
websocetObj
} from '@/http/websocet.js';
export default {
data() {
return {
}
},
onLoad() {
// 在onload的时候调用,创建webscoet连接对象,参数分别为:url、获取后端返回数据、监听websocket的链接失败返回的报错、监听链接状态,返回布尔值
websocetObj.sokcet('ws://服务器地址:端口/websocket', this.getWebsocetData, this.getWebsocetError, this.onErrorSucceed)
},
//离开页面销毁websocket
beforeDestroy() {
websocetObj.stop();
},
methods: {
//websocet函数回调:返回监听的数据
getWebsocetData(val) {
// val = String.fromCharCode.apply(null, new Uint8Array(val)).trim() //如果后端返回数据格式是其他的,可能需要转换一下,比如这个,应该是转Unicode编码
console.log(val, '函数回调');
// this.scanCode = val;
},
//websocet函数抛错: 返回错误信息 用于用户提示
getWebsocetError(err) {
this.socketShow = err.isShow;
this.webtext = err.messge;
console.log('websocet函数抛错', this.socketShow);
},
//websocet函数成功进入: 监听连接状态,在失败的时候弹窗提示,具体需求看自身情况
onErrorSucceed(val) {
this.socketShow = val.isShow;
console.log('websocet函数成功进入', this.socketShow);
}
}
}
</script>
结果
前台
后台
需要注意的是,如果使用wss协议的
如果是微信小程序,必须添加合法域名
vue
地址一定要,wss://域名/websocket
服务器
1、 安装 SSL 证书
您需要在服务器上安装有效的 SSL 证书,以启用 HTTPS 协议。如果您已经安装了 SSL 证书,请确保证书配置正确,并且证书链完整。如果您没有安装 SSL 证书,可以考虑购买或使用免费的证书,例如 Let's Encrypt。
解决方法官方推荐反向代理,地址
要还修改一些环境配置,具体就不写了,需要可以私聊....记得要清理游览器或者小程序缓存
不然会出现下面的错误,链接到了,可是加密文件不对
本人踩了很多坑,还有啥问题,可以提出来