一、在tp6项目下安装 GatewayWorker
composer require topthink/think-worker
composer require workerman/gatewayclient
安装成功后在配置文件目录下会出现gateway_worker.php
开始配置gateway_worker 下边我贴出了我的配置文件供大家参考
return [
// 扩展自身需要的配置
'protocol' => 'websocket', // 协议 支持 tcp udp unix http websocket text
'host' => '127.0.0.1', // 监听地址
'port' => 9099, // 监听端口
'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' => 1,
'pingData' => '{"type":"ping"}',
// BusinsessWorker配置
'businessWorker' => [
'name' => 'BusinessWorker',
'count' => 1,
'eventHandler' => 'app\common\service\WsEventService',
],
];
下面对gateway 配置部分的属性解释
name : 可以设置Gateway进程的名称,方便status命令中查看统计
count :可以设置Gateway进程的数量,以便充分利用多cpu资源
lanIp :lanIp是Gateway所在服务器的内网IP,如果不做多服务器分布式部署的话默认填写127.0.0.1即可
startPort :官方文档是这样说的 Gateway进程启动后会监听一个本机端口,用来给BusinessWorker提供链接服务,然后Gateway与BusinessWorker之间就通过这个连接通讯。这里设置的是Gateway监听本机端口的起始端口。比如启动了4个Gateway进程,startPort为2000,则每个Gateway进程分别启动的本地端口一般为2000、2001、2002、2003。
官方的话比较绕,其实就可以理解为一下配置了 N个端口 起始端口是 你配置的端口号 至于会启动多少个完全取决你配置的工作进程数 "count"
registerAddress : 注册服务地址
daemonize : 是否以守护进程模式启动(linux下有效 )
pingInterval :心跳间隔时间
pingNotResponseLimit : 服务端是否允许客户端不发送心跳 如果配置为0则服务端允许客户端不发心跳 ,如果配置为1 客户端必须要在心跳间隔时间(pingInterval)内发送心跳到服务器否则服务器会判定客户端断开而终端连接触发onclose事件。
pingData : 如果pingData 不是空字符串则服务器会在心跳间隔时间(pingInterval)向客户端发送心跳数据
PS:GatewayWorker 通过pingInterval、pingNotResponseLimit、pingData 这三个配置实现了心跳检测机制 ,详情请参见官方文档心跳检测部分 心跳检测-gateway-worker手册
下面对 businessWorker 的配置进行讲解
name :businessWorker启动的进程名
count :businessWorker启动的工作进程数
eventHandler : businessWorker 的事件类(这里要写完整的命名空间)
以下是eventHandler 的示例代码
namespace app\common\service;
use GatewayWorker\Lib\Gateway;
class WsEventService{
public static function onConnect($client_id)
{
Gateway::sendToCurrentClient("Your client_id is $client_id");
}
public static function onMessage($client_id , $data){
Gateway::sendtoCurrentClient("client_id: $client_id -> "."data => $data");
}
}
当然这里还可以配置更多的事件 详情请参照官方文档的Events类的回调属性-gateway-worker手册
至此我们就可以启动 gateway了
php think worker:gateway
如果你是在windows下会报错
这里不支持windows环境并不是说gateway worker不支持windows,而是tp的命令行运行方式不支持windows,原因是(在官方文档中有说明)
官方文档说要分别创建三个php文件分别启动 gateway、register、businessworker服务
我们这里可以通过一个TP自定义命令行搞定 继续上代码!
<?php
declare(strict_types=1);
namespace app\command;
use GatewayWorker\BusinessWorker;
use GatewayWorker\Gateway;
use GatewayWorker\Register;
use think\console\Command;
use think\console\Input;
use think\console\input\Argument;
use think\console\input\Option;
use think\console\Output;
use think\facade\Config;
use Workerman\Worker;
class WebSocket extends Command
{
protected function configure()
{
// 指令配置
$this->setName('wserver')
->addArgument('service', Argument::OPTIONAL, 'workerman service: gateway|register|businessworker', null)
->addOption('host', 'H', Option::VALUE_OPTIONAL, 'the host of workerman server', null)
->addOption('port', 'P', Option::VALUE_OPTIONAL, 'the port of workerman server', null)
->addOption('daemon', 'd', Option::VALUE_OPTIONAL, 'Run the workerman server in daemon mode.')
->setDescription('workerman Server for ThinkPHP');
}
protected function execute(Input $input, Output $output)
{
$service = $input->getArgument('service');
$option = Config::get('gateway_worker');
if ($input->hasOption('host')) {
$host = $input->getOption('host');
} else {
$host = !empty($option['host']) ? $option['host'] : '0.0.0.0';
}
if ($input->hasOption('port')) {
$port = $input->getOption('port');
} else {
$port = !empty($option['port']) ? $option['port'] : '2347';
}
$registerAddress = !empty($option['registerAddress']) ? $option['registerAddress'] : '127.0.0.1:1236';
switch ($service) {
case 'register':
$this->register($registerAddress);
break;
case 'businessworker':
$this->businessWorker($registerAddress, isset($option['businessWorker']) ? $option['businessWorker'] : []);
break;
case 'gateway':
$this->gateway($registerAddress, $host, $port, $option);
break;
default:
$output->writeln("<error>Invalid argument action:{$service}, Expected gateway|register|businessworker .</error>");
exit(1);
break;
}
Worker::runAll();
}
/**
* 启动register
* @access public
* @param string $registerAddress
* @return void
*/
public function register($registerAddress)
{
// 初始化register
new Register('text://' . $registerAddress);
}
/**
* 启动businessWorker
* @access public
* @param string $registerAddress registerAddress
* @param array $option 参数
* @return void
*/
public function businessWorker($registerAddress, $option = [])
{
// 初始化 bussinessWorker 进程
$worker = new BusinessWorker();
$this->option($worker, $option);
$worker->registerAddress = $registerAddress;
}
/**
* 启动gateway
* @access public
* @param string $registerAddress registerAddress
* @param string $host 服务地址
* @param integer $port 监听端口
* @param array $option 参数
* @return void
*/
public function gateway($registerAddress, $host, $port, $option = [])
{
// 初始化 gateway 进程
if (!empty($option['socket'])) {
$socket = $option['socket'];
unset($option['socket']);
} else {
$protocol = !empty($option['protocol']) ? $option['protocol'] : 'websocket';
$socket = $protocol . '://' . $host . ':' . $port;
unset($option['host'], $option['port'], $option['protocol']);
}
$gateway = new Gateway($socket, isset($option['context']) ? $option['context'] : []);
// 以下设置参数都可以在配置文件中重新定义覆盖
$gateway->name = 'Gateway';
$gateway->count = 4;
$gateway->lanIp = '127.0.0.1';
$gateway->startPort = 2000;
$gateway->pingInterval = 10;
$gateway->pingNotResponseLimit = 1;
$gateway->pingData = '{"type":"ping"}';
$gateway->registerAddress = $registerAddress;
// 全局静态属性设置
foreach ($option as $name => $val) {
if (in_array($name, ['stdoutFile', 'daemonize', 'pidFile', 'logFile'])) {
Worker::${$name} = $val;
unset($option[$name]);
}
}
$this->option($gateway, $option);
}
/**
* 设置参数
* @access protected
* @param Worker $worker Worker对象
* @param array $option 参数
* @return void
*/
protected function option($worker, array $option = [])
{
// 设置参数
if (!empty($option)) {
foreach ($option as $key => $val) {
$worker->$key = $val;
}
}
}
}
下边我们就可以通过运行这个tp自定义命令来分别启动三个服务
php think wserver register //启动 register服务
php think wserver businessworker //启动 businessworker服务
php think wserver gateway //启动 gateway服务
这样我们需要在windows上打开三个cmd窗体分别执行这三条命令 如果嫌麻烦的话可以编辑个bat脚本一次启动这三个服务, 将下边代码保存成 xxx.bat 就可以了
start php think wserver register
start php think wserver businessworker
start php think wserver gateway
最后执行这个bat脚本就可以了(通过命令行执行或者双击执行都可以)
到这里我们就可以在tp6项目中任何一个地方通过调用 GatewayWorker\Lib\Gateway 类的方法向客户端推送消息了 详情请参见官方文档 Lib/Gateway类提供的接口-gateway-worker手册文章来源:https://www.toymoban.com/news/detail-722700.html
Gateway::sendToClient($client_id,$message);
windows 启动服务部分参照了 八戒王的博客《GatewayWorker Not Support On Windows.》 特此鸣谢!GatewayWorker Not Support On Windows._windows不支持 geteway_八戒王的博客-CSDN博客文章来源地址https://www.toymoban.com/news/detail-722700.html
到了这里,关于TP6 + GatewayWorker 轻松实现web项目 websocket 功能的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!