Thinkphp6配置使用Workerman WebSocket Socket
发布时间:2022-06-23, 17:46:28 分类:PHP | 编辑 off 网址 | 辅助
图集1/3
正文 2397字数 502,624阅读
首先通过 composer 安装
composer require topthink/think-worker
Run code
Cut to clipboard
windows 服务器需要下载的
composer require workerman/workerman-for-win
Run code
Cut to clipboard
安装成功后config 目录下,会多出几个文件
打开worker_server.php 我们看到他默认的监听端口是2345,下面虽然也提供了一些回调方法,但是毕竟是在配置文件中,我们也不太好扩展,所以我们这时需要自定义workerman服务类
步骤如下:
新建一个应用,比如命名为http,然后新建一个php 类 Worker.php
<?php
namespace app\http;
use think\worker\Server;
class Worker extends Server
{
protected $socket = 'websocket://localhost:2345';
public function onMessage($connection, $data)
{
$connection->send("已经收到");
}
/**
* 当连接建立时触发的回调函数
* @param $connection
*/
public function onConnect($connection)
{
$connection->send("连接成功");
}
/**
* 当连接断开时触发的回调函数
* @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)
{
}
}
Run code
Cut to clipboard
然后在回到刚才的配置文件worker_server.php,修改worker_class 为你刚才创建的类,定义该参数后,其它配置参数均不再有效。
在worker_server.php中增加配置参数:
return [
'worker_class' => 'app\http\Worker',
];
Run code
Cut to clipboard
使用Workerman作为HttpServer,启动服务端,至此我们的服务端已经搭建完成了
php think worker:server
Run code
Cut to clipboard
我们可以新建一个html ,查看一下是否可以正常使用
<html>
<head>
<meta charset="utf-8" />
<title>网页版群聊</title>
</head>
<body>
<script>
ws = new WebSocket("ws://localhost:2345");
ws.onopen = function() {
console.info("webSocket通道建立成功!!!");
ws.send('hello');
console.log("给服务端发送一个字符串:hello");
};
ws.onmessage = function(even) {
console.log("收到服务端的消息:" + even.data);
};
</script>
</body>
</html>
Run code
Cut to clipboard
Thinkphp6.x 如何配置使用 Workerman
WebSocket 在线测试
在 ThinkPHP6 中使用 Workerman
thinkphp6整合workerman教程
thinkPHP6+workerman即时通讯小demo
Composer 中文网
workerman手册
ThinkPHP6.0 Workerman 手册
(支付宝)给作者钱财以资鼓励 (微信)→
有过 4 条评论 »
修改 php.ini track_errors=On 为 track_errors=Off 即可
The Windows OneDrive folder is not supported on PHP versions below 7.2.23 an
windows下安装composer
Could not find package topthink/think-worker. It was however found via repos
Composer更改为阿里的源
composer config -g repo.packagist composer https://mirrors.aliyun.com/composer/
解除镜象
composer config -g --unset repos.packagist
解决PHP Warning: Module 'mysqli' already loaded in Unknown on line 0
原因:是PHP有两种方式添加扩展模块,一种是直接编译进了PHP,另外一种是通过共享模式添加模块,并在php.ini配置文件中配置相应的模块。以上问题出现的原因是我们需要的模块已经编译进PHP了,但是我们有通过共享模块再次加重了改模块,这样就导致重复加重。
在php.ini中找到下面并注释
;extension=mysqli
使用php -m还是可以看到mysqli扩展的,并且不会再报刚才的错误
websocket连接之后,如果隔一段时间不聊天,运营商会认为你空占网络资源,强行关闭你的websocket连接,
如果想要一直保持连接,就需要监听websocket关闭事件,等关闭时重新连接从而让websocket一直保持连接.
这个过程称为心跳
1、必须要有心跳,如果没有会自动断开连接。
2‘、断开后必须取消setTimeout,不然会继续执行一次。
3、发送消息只有在onSocketOpen后才会发送,所以添加一个消息数组,等连接成功后再发送。
4、如果在还没连接成功时退出连接,会导致无法关闭,所以添加了socketClose来关闭socket
// socket已经连接成功 var socketOpen = false // socket已经调用关闭function var socketClose = false // socket发送的消息队列 var socketMsgQueue = [] // 判断心跳变量 var heart = '' // 心跳失败次数 var heartBeatFailCount = 0 // 终止心跳 var heartBeatTimeOut = null; // 终止重新连接 var connectSocketTimeOut = null; var webSocket = { /** * 创建一个 WebSocket 连接 * @param {options} * url String 是 开发者服务器接口地址,必须是 wss 协议,且域名必须是后台配置的合法域名 * header Object 否 HTTP Header , header 中不能设置 Referer * method String 否 默认是GET,有效值:OPTIONS, GET, HEAD, POST, PUT, DELETE, TRACE, CONNECT * protocols StringArray 否 子协议数组 1.4.0 * success Function 否 接口调用成功的回调函数 * fail Function 否 接口调用失败的回调函数 * complete Function 否 接口调用结束的回调函数(调用成功、失败都会执行) */ connectSocket: function(options) { wx.showLoading({ title: '', mask: true, }) socketOpen = false socketClose = false socketMsgQueue = [] wx.connectSocket({ url: '开发者服务器接口地', success: function(res) { if (options) { // 成功回调 options.success && options.success(res); } }, fail: function(res) { if (options) { // 失败回调 options.fail && options.fail(res); } } }) }, /** * 通过 WebSocket 连接发送数据 * @param {options} * data String / ArrayBuffer 是 需要发送的内容 * success Function 否 接口调用成功的回调函数 * fail Function 否 接口调用失败的回调函数 * complete Function 否 接口调用结束的回调函数(调用成功、失败都会执行) */ sendSocketMessage: function(options) { if (socketOpen) { wx.sendSocketMessage({ data: options.msg, success: function(res) { if (options) { options.success && options.success(res); } }, fail: function(res) { if (options) { options.fail && options.fail(res); } } }) } else { socketMsgQueue.push(options.msg) } }, /** * 关闭 WebSocket 连接。 * @param {options} * code Number 否 一个数字值表示关闭连接的状态号,表示连接被关闭的原因。如果这个参数没有被指定,默认的取值是1000 (表示正常连接关闭) * reason String 否 一个可读的字符串,表示连接被关闭的原因。这个字符串必须是不长于123字节的UTF-8 文本(不是字符) * fail Function 否 接口调用失败的回调函数 * complete Function 否 接口调用结束的回调函数(调用成功、失败都会执行) */ closeSocket: function(options) { if (connectSocketTimeOut) { clearTimeout(connectSocketTimeOut); connectSocketTimeOut = null; } socketClose = true; var self = this; self.stopHeartBeat(); wx.closeSocket({ success: function(res) { console.log('WebSocket 已关闭!'); if (options) { options.success && options.success(res); } }, fail: function(res) { if (options) { options.fail && options.fail(res); } } }) }, // 收到消息回调 onSocketMessageCallback: function(msg) { }, // 开始心跳 startHeartBeat: function() { console.log('socket开始心跳') var self = this; heart = 'heart'; self.heartBeat(); }, // 结束心跳 stopHeartBeat: function() { console.log('socket结束心跳') var self = this; heart = ''; if (heartBeatTimeOut) { clearTimeout(heartBeatTimeOut); heartBeatTimeOut = null; } if (connectSocketTimeOut) { clearTimeout(connectSocketTimeOut); connectSocketTimeOut = null; } }, // 心跳 heartBeat: function() { var self = this; if (!heart) { return; } self.sendSocketMessage({ msg: JSON.stringify({ 'msg_type': 'heart' }), success: function(res) { console.log('socket心跳成功'); if (heart) { heartBeatTimeOut = setTimeout(() => { self.heartBeat(); }, 7000); } }, fail: function(res) { console.log('socket心跳失败'); if (heartBeatFailCount > 2) { // 重连 self.connectSocket(); } if (heart) { heartBeatTimeOut = setTimeout(() => { self.heartBeat(); }, 7000); } heartBeatFailCount++; }, }); } } // 监听WebSocket连接打开事件。callback 回调函数 wx.onSocketOpen(function(res) { console.log('WebSocket连接已打开!') wx.hideLoading(); // 如果已经调用过关闭function if (socketClose) { webSocket.closeSocket(); } else { socketOpen = true for (var i = 0; i < socketMsgQueue.length; i++) { webSocket.sendSocketMessage(socketMsgQueue[i]) } socketMsgQueue = [] webSocket.startHeartBeat(); } }) // 监听WebSocket错误。 wx.onSocketError(function(res) { console.log('WebSocket连接打开失败,请检查!', res) }) // 监听WebSocket接受到服务器的消息事件。 wx.onSocketMessage(function(res) { console.log('收到服务器内容:' + res.data) webSocket.onSocketMessageCallback(res.data) }) // 监听WebSocket关闭。 wx.onSocketClose(function(res) { console.log('WebSocket 已关闭!') if (!socketClose) { clearTimeout(connectSocketTimeOut) connectSocketTimeOut = setTimeout(() => { webSocket.connectSocket(); }, 3000); } }) module.exports = webSocket;
下面是使用方法
// socket连接 const webSocket = require('../../utils/webSocket.js'); onLoad: function(options) { // 创建连接 webSocket.connectSocket(); // 设置接收消息回调 webSocket.onSocketMessageCallback = this.onSocketMessageCallback; }, // socket收到的信息回调 onSocketMessageCallback: function(msg) { console.log('收到消息回调', msg) }, onUnload: function(options) { // 页面销毁时关闭连接 webSocket.closeSocket(); },
private function write_log($data){ $years = date('Y-m'); //设置路径目录信息 $url = './public/log/txlog/'.$years.'/'.date('Ymd').'_request_log.txt'; $dir_name=dirname($url); //目录不存在就创建 if(!file_exists($dir_name)) { //iconv防止中文名乱码 $res = mkdir(iconv("UTF-8", "GBK", $dir_name),0777,true); } $fp = fopen($url,"a");//打开文件资源通道 不存在则自动创建 fwrite($fp,var_export($data,true)."\r\n");//写入文件 fclose($fp);//关闭资源通道 }
创建wss服务