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

ThinkPHP6 集成TCP长连接 GatewayWorker

概述

ThinkPHP是一个免费开源的,快速、简单的面向对象的轻量级PHP开发框架,是为了敏捷WEB应用开发和简化企业应用开发而诞生的。

GatewayWorker是基于Workerman开发的一套TCP长连接的应用框架,实现了单发、群发、广播等接口,内置了mysql类库,GatewayWorker分为Gateway进程和Worker进程,天然支持分布式部署。

Workerman 是一款纯 PHP 开发的开源高性能的 PHP socket 服务器框架。而think-worker则是 ThinkPHP 官方发布的一个workerman扩展,从2.0+版本完善了对Workerman的支持。

安装

Step.1 安装 Think-worker

首先通过 composer 安装

composer require topthink/think-worker

事实上在安装think-worker扩展的时候会自动安装workerman依赖包,所以直接在你的项目根目录下运行下面的命令安装扩展,如果你还没有安装workerman的话也会自动安装。

如果你是第一次使用ThinkPHP6.0,那么可以先创建一个初始项目,然后再安装扩展,依次执行下面的命令即可。

composer create-project topthink/think tp6
cd tp6
composer require topthink/think-worker

Step.2 安装 GatewayWorker

首先确保你已经安装了GatewayWorker,如果还没有,可以使用下面的命令安装

composer require workerman/gateway-worker

接下来,可以直接在命令行运行

php think worker:gateway

会显示下面的信息,表示启动成功。

Starting GatewayWorker server...
Workerman[think] start in DEBUG mode
-------------------------------------------- WORKERMAN ---------------------------------------------
Workerman version:3.5.35          PHP version:7.4.8           Event-Loop:\Workerman\Events\Select
--------------------------------------------- WORKERS ----------------------------------------------
proto   user            worker            listen                      processes    status           
tcp     root            Register          text://127.0.0.1:1236       1             [OK]            
tcp     root            BusinessWorker    none                        1             [OK]            
tcp     root            thinkphp          websocket://0.0.0.0:8888    1             [OK]            
----------------------------------------------------------------------------------------------------
Press Ctrl+C to stop. Start success.

Step.3 守护进程模式

如果需要使用守护进程模式,可以使用

php think worker:gateway -d

同样支持在命令行指定地址和端口

php think worker:gateway -H tinywan.com -p 2800

配置文件

如果需要调整配置,可以修改配置目录下面的config/gateway_worker.php文件,内容如下:

<?phpreturn [// 扩展自身需要的配置'protocol' => 'websocket', // 协议 支持 tcp udp unix http websocket text'host' => '0.0.0.0', // 监听地址'port' => 8888, // 监听端口'socket' => '', // 完整监听地址'context' => [], // socket 上下文选项'register_deploy' => true, // 是否需要部署register'businessWorker_deploy' => true, // 是否需要部署businessWorker'gateway_deploy' => true, // 是否需要部署gateway// Register配置'registerAddress' => '127.0.0.1:1236',// Gateway配置'name' => 'thinkphp','count' => 1,'lanIp' => '127.0.0.1','startPort' => 2000,'daemonize' => false,'pingInterval' => 30,'pingNotResponseLimit' => 0,'pingData' => '{"type":"ping"}',// BusinsessWorker配置'businessWorker' => ['name' => 'BusinessWorker','count' => 1,'eventHandler' => \app\common\Events::class],];

默认配置参数如果需要更改,可以直接修改。

注:GatewayWorker开发过程中首先要配置BusinessWorker下面的eventHandler参数。系统默认提供了一个think\worker\Events类作为参考,实际请根据需要进行调整。详细用法请参考 GatewayWorker手册。

业务 Events 文件

<?php
/*** @desc 业务开发只需要关注 Events.php 一个文件即可* @author Tinywan(ShaoBo Wan)*/
declare(strict_types=1);namespace app\common;use GatewayWorker\Lib\Gateway;
use Workerman\Worker;class Events
{/*** onWorkerStart 事件回调* 当businessWorker进程启动时触发。每个进程生命周期内都只会触发一次* @access public* @param Worker $businessWorker* @return void*/publicstaticfunction onWorkerStart(Worker $businessWorker){}/*** onConnect 事件回调* 当客户端连接上gateway进程时(TCP三次握手完毕时)触发* @access public* @param string $client_id* @return void*/publicstaticfunction onConnect(string $client_id){Gateway::sendToCurrentClient("你的客户端ID是: $client_id");}/*** onWebSocketConnect 事件回调* 当客户端连接上gateway完成websocket握手时触发* @param string $client_id 断开连接的客户端client_id* @param mixed $data* @return void*/publicstaticfunction onWebSocketConnect(string $client_id, $data){var_export($data);}/*** onMessage 事件回调* 当客户端发来数据(Gateway进程收到数据)后触发* @access public* @param string $client_id* @param mixed $data* @return void* @throws \Exception*/publicstaticfunction onMessage(string$client_id, $data){Gateway::sendToAll('开源技术小栈:'.$data);}/*** onClose 事件回调 当用户断开连接时触发的方法* @param string $client_id 断开连接的客户端client_id* @return void* @throws \Exception*/publicstaticfunction onClose(string $client_id){GateWay::sendToAll("client[$client_id] logout\n");}/*** onWorkerStop 事件回调* 当businessWorker进程退出时触发。每个进程生命周期内都只会触发一次。* @param Worker $businessWorker* @return void*/publicstaticfunction onWorkerStop(Worker $businessWorker){echo"WorkerStop\n";}
}

本地调式

以上就把服务启动好了,接下来在本地调式,在桌面创建一个html文件,名字随意,我这里命名为websocket.html,打开文件复制以下代码替换:

<!DOCTYPE html>
<html>
<head><meta charset="utf-8"/><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1"><title>开源技术小栈</title><style>body {font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;font-size: 22px;}.btn-group {display: inline-block;}</style>
</head>
<body>
<div><input type='text' value='通信地址, ws://开头..' class="form-control" style='width:390px;display:inline' id='wsaddr'/><div class="btn-group"><button type="button" class="btn btn-default" onclick='addsocket();'>连接</button><button type="button" class="btn btn-default" onclick='closesocket();'>断开</button><button type="button" class="btn btn-default" onclick='$("#wsaddr").val("")'>清空</button></div><div class="row"><div id="output" style="border:1px solid #ccc;height:385px;overflow: auto;margin: 20px 0;"></div><input type="text" id='message' class="form-control" style='width:365px' placeholder="待发信息"onkeydown="en(event);"><span class="input-group-btn"><button class="btn btn-default" type="button" onclick="doSend();">发送</button></span></div>
</div>
</body><script src="https://code.jquery.com/jquery-3.1.1.min.js"></script>
<script language="javascript" type="text/javascript">function formatDate(now) {var year = now.getFullYear();var month = now.getMonth() + 1;var date = now.getDate();var hour = now.getHours();var minute = now.getMinutes();var second = now.getSeconds();return year + "-" + (month = month < 10 ? ("0" + month) : month) + "-" + (date = date < 10 ? ("0" + date) : date) +" " + (hour = hour < 10 ? ("0" + hour) : hour) + ":" + (minute = minute < 10 ? ("0" + minute) : minute) + ":" + (second = second < 10 ? ("0" + second) : second);}var output;var websocket;function init() {output = document.getElementById("output");testWebSocket();}function addsocket() {var wsaddr = $("#wsaddr").val();if (wsaddr == '') {alert("请填写websocket的地址");returnfalse;}StartWebSocket(wsaddr);}function closesocket() {websocket.close();}function StartWebSocket(wsUri) {websocket = new WebSocket(wsUri);websocket.onopen = function (evt) {onOpen(evt)};websocket.onclose = function (evt) {onClose(evt)};websocket.onmessage = function (evt) {onMessage(evt)};websocket.onerror = function (evt) {onError(evt)};}function onOpen(evt) {writeToScreen("<span style='color:red'>连接成功,现在你可以发送信息啦!!!</span>");}function onClose(evt) {writeToScreen("<span style='color:red'>websocket连接已断开!!!</span>");websocket.close();}function onMessage(evt) {writeToScreen('<span style="color:blue">服务端回应&nbsp;' + formatDate(newDate()) + '</span><br/><span class="bubble">' +evt.data + '</span>');}function onError(evt) {writeToScreen('<span style="color: red;">发生错误:</span> ' + evt.data);}function doSend() {var message = $("#message").val();if (message == '') {alert("请先填写发送信息");$("#message").focus();returnfalse;}if (typeof websocket === "undefined") {alert("websocket还没有连接,或者连接失败,请检测");returnfalse;}if (websocket.readyState == 3) {alert("websocket已经关闭,请重新连接");returnfalse;}console.log(websocket);$("#message").val('');writeToScreen('<span style="color:green">你发送的信息&nbsp;' + formatDate(newDate()) + '</span><br/>' + message);websocket.send(message);}function writeToScreen(message) {var div = "<div class='newmessage'>" + message + "</div>";var d = $("#output");var d = d[0];var doScroll = d.scrollTop == d.scrollHeight - d.clientHeight;$("#output").append(div);if (doScroll) {d.scrollTop = d.scrollHeight - d.clientHeight;}}function en(event) {var evt = evt ? evt : (window.event ? window.event : null);if (evt.keyCode == 13) {doSend()}}
</script>
</html>

图片

如果服务器有回调信息,证明整个服务搭建完毕

http://www.dtcms.com/a/540037.html

相关文章:

  • TMap的查询
  • SpringCloud--Sleuth 解析
  • 【C++:继承和多态】多态加餐:面试常考——多态的常见问题11问
  • 零基础新手小白快速了解掌握服务集群与自动化运维(十五)Redis模块-哨兵集群
  • 今日Cortex-M3/M4研究总结
  • 2014吉林省赛题解 | CCUT应用OJ题解——Sign in
  • 涿州网站建设推广浙江建筑信息网站
  • 前端性能优化实战指南:从首屏加载到用户体验的全面提升
  • 【OPENGL ES 3.0 学习笔记】第十一天:glDrawArrays和glDrawElements
  • Linux入门1(2/2)
  • ubuntu24安装mysql遇到的坑----解决Mysql报错缺少libaio.so.1
  • 【星光不负 码向未来 | 万字解析:基于ArkUI声明式UI与分布式数据服务构建生产级跨设备音乐播放器】
  • UniApp 在手机端(Android)打开选择文件和文件写入
  • HarmonyOS分布式媒体播放器——跨设备音视频无缝流转
  • 【金融行业案例】基于Vaadin全栈Java框架重构内部系统,全面提升开发效率与用户体验
  • 小型网站开发要多少钱苏州专业做网站的公司哪家好
  • RocketMQ 生产环境性能调优实战:从 0 到 1 打造高可用消息队列系统
  • 脉冲按摩贴方案开发, 脉冲按摩贴MCU控制方案设计
  • 特别酷炫网站做网站有费用吗
  • DrissionPage 基于 Python 的网页自动化工具
  • Next.js vs Vue.js:2025年全栈战场,谁主沉浮?
  • DAY01笔记
  • 10-js基础(ESMAScript)
  • 一次深入排查:Spring Cloud Gateway TCP 连接复用导致 K8s 负载均衡失效
  • 基于 Vue3 及TypeScript 项目后的总结
  • Android下解决滑动冲突的常见思路是什么?
  • 建筑外观设计网站如何做一个门户网站
  • SQL多表查询完全指南-从JOIN到复杂关联的数据整合利器
  • Redis主从复制与哨兵集群
  • 电科金仓“异构多活架构”:破解浙江省人民医院集团化信创难题的密钥