关于swoole:Swoole-51-增加更多数据库协程客户端支持

在 5.1 版本中减少了多种数据库协程客户端的反对,并且全副以 PDO 接口的形式提供,旧的业务代码无需做任何更改即可一键切换为协程模式,异步非阻塞地并发执行。 包含: pdo_pgsqlpdo_odbcpdo_sqlitepdo_oci (Oracle 数据库)开启办法减少了 4 个编译参数和 Runtime Hook 选项,开启这些协程客户端。 编译选项--with-swoole-odbc,依赖 unixodbc-dev--with-swoole-pgsql,依赖 libpq-dev--with-swoole-sqlite,依赖 libsqlite3-dev--with-swoole-oracle,依赖 oracle-instantclientRuntime Hook 选项SWOOLE_HOOK_PDO_PGSQLSWOOLE_HOOK_PDO_ODBCSWOOLE_HOOK_PDO_SQLITESWOOLE_HOOK_PDO_ORACLE这些选项已蕴含在 SWOOLE_HOOK_ALL 中,也可独自启用其中一个客户端。 PDO_PGSQL在之前的版本中,提供了 Swoole\Coroutine\PostgreSQL 客户,因为是全新的 API,用户须要兼容 PHP-FPM 和 Swoole,应用并不宽泛。 go(function () { $pg = new Swoole\Coroutine\PostgreSql(); $conn = $pg->connect("host=127.0.0.1 port=5432 dbname=test user=test password="); $result = $pg->query($conn, 'SELECT * FROM test;'); $arr = $pg->fetchAll($result); var_dump($arr);});5.1 版本中减少了 Runtime Hook PDO_PGSQL,能够间接应用 FPM 下的历史代码。 go(function () { $pdo = new PDO("pgsql:host={$host};port={$port};dbname={$dbname}", $user, $password); $statement = $pdo->query('select * from user where id =1 limit 1'); var_dump($statement->fetch(PDO::FETCH_ASSOC));});PDO_ODBCODBC(Open Database Connectivity)是一种为多种数据库管理系统提供对立接口的标准化技术。它是由微软公司提出的,目标是为了实现异构性,使得应用程序可能拜访多种不同类型的数据源。 ODBC 的规范定义了应用程序发出请求的 API,以及由驱动程序提供的响应申请的 API。ODBC 是一种凋谢的、跨平台的技术,能够在多种操作系统和编程语言中应用。 ...

June 9, 2023 · 2 min · jiezi

关于swoole:比df更好用的命令

大家好,我是良许。 对于剖析磁盘应用状况,有两个十分好用的命令:du 和 df 。简略来说,这两个命令的作用是这样的: du 命令:它是英文单词 disk usage 的简写,次要用于查看文件与目录占用多少磁盘空间;df 命令:它是英文单词 disk free 的简写,次要用于查看磁盘被应用了多少空间、残余多少空间,等等。特地是你在磁盘爆满的状况下,这两个命令联合起来十分好用。 然而,这两个命令毕竟是离开的,要是能整合起来该多好,毕竟都是同类型的命令。 别说,还真有人把这两个命令整合起来,它就是:duf 命令! duf 是一个用 Golang 编写的跨磁盘应用状况离别工具,它能够以表格(自适应)的模式输入磁盘应用状况,而且还能够依据需要对后果进行排序,应用十分不便! 1. duf命令的装置以 Ubuntu 为例,咱们不能间接应用 apt-get 命令装置,须要手动装置。 首先,从 GitHub 上下载 duf 命令的安装包: $ wget https://github.com/muesli/duf/releases/download/v0.8.1/duf_0.8.1_linux_amd64.deb而后,再应用 dpkg 命令装置: $ dpkg -i duf_0.8.1_linux_amd64.debmacOS 平台装置: $ brew install duf或者$ sudo port selfupdate && sudo port install dufWindows 平台装置: choco install duf或者scoop install duf2. duf命令的应用最根本的应用,就是间接 duf 三个字母,不加任何参数,非常简单。这种用法会输入所有本地设施、已挂载的任何云存储设备以及任何其余非凡设施(包含长期存储地位等)的详细信息。 $ duf 能够看到,它是以黑白及可视化符号模式显示磁盘应用状况(在 Ubuntu 自带终端工具下),十分直观,也十分养眼。 这里信息毕竟有点多,如果你只想查看本地设施磁盘应用信息,能够加上 --only local 选项: ...

March 14, 2023 · 1 min · jiezi

关于swoole:Swoole-的异步-Task-任务详解

本文将从上面两方面讲述 Swoole Task 工作: 1.如何在 Swoole 中实现异步 Task 工作? 2.Swoole 的异步 Task 工作在 CRMEB 电商零碎中的应用场景有哪些? 一、如何在 Swoole 中实现异步 Task 工作?如果一些耗时的操作要在服务器端程序中执行 (例如,在 Web 服务器中发送电子邮件和短消息等。),如果间接按程序执行这些操作,程序会阻塞以后过程,导致服务器响应迟缓。通常的做法是应用异步脚本或音讯队列来实现这些操作。如何通过 Swoole 实现异步工作解决? Swoole 提供了异步解决的性能,能够将一个异步工作公布到 TaskWorker 过程池中执行,而不影响以后申请的处理速度。 新建文件,命名为 task_server.php,代码如下: 在命令行执行如下命令即可运行程序: php task_server.php 下面的代码创立了一个 TCP 服务,同时设置了四个 taskWorker 过程,实现了两个事件回调函数 onTask 和 onfinish。当客户端与服务器建设连贯时,客户端发送的音讯将触发下面代码中的 receive 事件。在 receive 事件中,会调用 $serv->task () 函数来执行工作,程序会立刻返回,持续向下执行代码。OnTask 回调函数在 TaskWorker 过程中异步执行。执行后调用 $serv->finish () 函数返回后果 (finish 回调函数是可选事件,能够不设置)。 二、Swoole 的 Task 工作适宜解决一些耗时的操作,如发送邮件、发送短信、推送音讯等。例如在下面代码中,onReceive 回调事件被触发后,就能够执行 $serv->task () 来执行一个异步工作。 注意事项: 如果要投递工作,须要在配置文件中 task_worker_num 必须要设置,否则会报错 ...

September 29, 2022 · 1 min · jiezi

关于swoole:基于-Swoole-搭建-WebSocket-服务详解

本节将会详解以下 4 个问题: 什么是 swoole? 什么是 Websocket? 如何基于 Swoole 构建 WebSocket 服务? 基于 Swoole 的 WebSocket 服务和 Http 服务是什么关系? 一、 Swoole 简介Swoole 是一个面向生产环境的 PHP 异步网络通信引擎,使 PHP 开发人员可能编写高性能的异步并发 TCP、UDP、Unix Socket、HTTP 和 WebSocket 服务。Swoole 可广泛应用于互联网、挪动通信、企业软件、云计算、网络游戏、物联网 (IOT)、车联网、智能家居等畛域。应用 PHP+Swoole 作为网络通信框架,能够大大提高企业 IT R&D 团队的工作效率。 Swoole 反对用于构建各种服务器,包含 HTTP 服务器、websocket 服务器、tcp 服务器、redis 服务器等等。咱们在这里应用 websocket 服务器。 二、WebSocket 介绍WebSocket 是通过繁多 TCP 连贯进行全双工通信的协定。WebSocket 通信协议在 2011 年被 IETF 指定为规范 RFC 6455,并由 RFC7936 进行了补充。WebSocket API 也被 W3C 指定为规范。WebSocket 使得客户端和服务器之间的数据交换更加容易,并容许服务器被动将数据推送到客户端。在 WebSocket API 中,浏览器和服务器只须要握手一次,就能够间接创立长久连贯,进行双向数据传输。 ...

September 26, 2022 · 1 min · jiezi

关于swoole:Swoole-进程模型分析

在这边文章中咱们将介绍以下内容: 1、Swoole Server 的运行模式 2、Swoole 过程模型剖析 上图是 Swoole 官网提供的各个过程互相关系图,能够说了解了这张图,你就了解了 Swoole 的过程模型。 1、Swoole Server 的运行模式 Swoole 服务常见的运行模式有单线程模式和过程模式两种,两种形式介绍如下: 单线程模式 (SWOOLE_BASE) 这种模式就是传统的异步非阻塞 Server,与 Nginx 和 Node.js 等异步服务的原理是一样的。在这种模式下,事件循环会间接回调 PHP 的函数,而不是通过线程 dispatch 投递工作。如果在回调函数中有阻塞操作,就会导致 Server 进化为同步模式。就像在上一篇文章中 Nginx+PHP-FPM 架构中介绍的那样,Nginx 只做转发,具体业务由 PHP-FPM 来实现。如果 Nginx 也能够解决业务逻辑,一旦呈现阻塞的业务逻辑,Nginx 的性能会急剧下降。正是因为 Nginx 和 PHP-FPM 所起到的作用不同,才会造就 Nginx 的高性能。Base 模式的特点:没有 Master 过程的角色;每个 Worker 过程同时承当了 Process 模式下 Reactor 线程和 Worker 过程两局部职责;在这种模式下,Manage 过程是可选的,当设置了 worker_num=1,并且么有应用 Task 和 MaxRequest 个性时,底层将间接创立一个独自的 Worker 过程,不创立 Manager 过程 Base 模式的长处:没有 IPC 开销,性能更好;代码简略,不容易出错。Base 模式的毛病:TCP 连贯时在 Worker 过程中维持的,所以当某个 Worker 过程挂掉时,此 Worker 内的所有连贯都将被敞开;大量 TCP 长连贯无奈利用到所有的 Worker 过程;TCP 连贯与 Worker 过程是绑定的,在长连贯利用中,不同的 Worker 过程无奈实现负载平衡。例如:某些连贯的数据量很大,这些连贯所在的 Worker 过程的负载会十分高。然而某些连贯数据量很小,所在 Worker 过程的负载会非常低。Base 模式实用场景:如果客户端连贯之间不须要交互,能够应用 Base 模式。如 Memcache、Http 服务等。 ...

September 21, 2022 · 1 min · jiezi

关于swoole:每个程序员都应该知道的-Swoole-知识-定时器

本节将讲述如下三个问题: PHP 自身的定时器介绍 Swoole 中定时器的应用办法 Swoole 定时器的底层原理 1、PHP 自身的定时器介绍先说说原生 PHP 如何实现定时器,PHP 的定时器是通过 pcntl_alarm 实现的: pcntl_alarm ( int $seconds ) : int pcntl_alarm 函数的作用是为过程设置一个 alarm 闹钟信号。调用这个办法后会创立一个计数器,在指定的秒数后向过程发送一个 SIGALRM 信号。每次对 pcntl_alarm 的调用都会勾销之前设置的 alarm 信号。 其中,$seconds 为期待的秒数,如果 $seconds 设置为 0,将不会创立 alarm 信号。调用这个函数后返回上次 alarm 调度残余的秒数,或者之前没有 alarm 调度时返回 0。 上面咱们看一个例子,pcntl_signal () 函数装置信号处理器,pcntl_signal_dispatch () 调用期待信号的处理器。 pcntl_alarm () 函数是基于时钟信号 + tick 函数实现的,存在一些缺点: 最大进反对到秒,而 Swoole Timer 能够到毫秒级别不反对同时设定多个定时器程序 pcntl_alarm () 依赖 declare (ticks = 1),性能很差 2、Swoole 中定时器的应用办法Swoole 中的定时器能够达到毫秒精度,同时能够反对增加大量定时器。 ...

September 5, 2022 · 1 min · jiezi

关于swoole:PHP-基于-SWX-框架搭建WebSocket服务器二

前言官网地址:SW-X框架-专一高性能便捷开发而生的PHP-SwooleX框架 心愿各大佬举起小手,给小弟一个star:https://github.com/swoolex/swoolex 1、前端模板最终要实现的成果,如下图: 该模板能够间接下载:练习WebSocket应用的前端html模板 也能够间接应用上面的前端代码,命名为:index.html <!DOCTYPE HTML><html><head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="renderer" content="webkit"> <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"> <title>SW-X | WebSocket客户端示例</title> <script src="https://blog.junphp.com/public/js/jquery.min.js"></script> <script src="jquery.md5.js"></script> <script src="tim.js"></script> <style>body,html{margin: 0;padding: 10px; height: calc(100% - 30px);font-size: 13px;}ul,li{list-style: none;padding: 0;margin: 0;}.user_list{width: 200px; height: 100%; overflow: hidden; overflow-y: auto; padding: 10px;border: 1px solid #ccc;float: left;}.user_list li{width: 100%;padding: 5px 0;cursor: pointer;}.user_list li:hover{color: #0077d6;}.main{width: calc(100% - 550px); height: 70%; overflow: hidden; overflow-y: auto; padding: 10px;border: 1px solid #ccc;float: left;border-left: 0;background: #e9f8ff;}.content{width: calc(100% - 530px); height: calc(30% - 1px);border: 1px solid #ccc;float: left;border-left: 0;border-top: 0;position: relative;}#content{width: calc(100% - 20px);;border: 0;height:calc(100% - 25px);padding: 10px;}#content:focus{outline: none;}code{padding: 3px 5px;border-radius: 30%; color: #fff;}.online{background: #35b700;}.offline{background: red;}.record{float: left;width: 100%;padding: 5px 0;}.record span{font-size: 12px; background: #ccc; border-radius: 5px; color: #0037ff;padding: 1px 3px;}.other p{text-indent: 30px;padding: 0px;}.own{text-align: right;}.tips{text-align: center;font-size: 12px; color: #e80000;}.drift{position: absolute;bottom: 10px; right: 10px; }#send{background: #009e3f;border: 1px solid #009020;font-size: 14px;padding: 3px 10px;color: #fff;border-radius: 5px;cursor: pointer;}#send:hover{background: #008234;border: 1px solid #005613;}#open{background: #009e97;border: 1px solid #007974;font-size: 14px;padding: 3px 10px;color: #fff;border-radius: 5px;cursor: pointer;}#open:hover{background: #008a84;border: 1px solid #00736e;}#close{background: #ef0000;border: 1px solid #c30000;font-size: 14px;padding: 3px 10px;color: #fff;border-radius: 5px;cursor: pointer;}#close:hover{background: #c50000;border: 1px solid #a00000;}input{padding: 4px;}.log{width: 326px;height: calc(100% - 40px);border: 1px solid #ccc;float: right;border-left: 0;position: absolute;right: 0;overflow: hidden;overflow-y: auto;}.log div{width: calc(100% - 20px);padding:10px 10px 0 10px;} </style> </head><body> <!--用户列表--> <div class="user_list"> <ul></ul> </div> <!--聊天窗口--> <div class="main"></div> <!--输出窗口--> <div class="content"> <textarea id="content"></textarea> <div class="drift"> <input id="host" type="text" placeholder="WS地址" style="width: 700px;"> <input id="user_id" type="text" placeholder="输出user_id"> <input id="username" type="text" placeholder="输出用户名"> <button id="open">连贯</button> <button id="close">断开</button> <button id="send">发送</button> </div> </div> <!--交互记录--> <div class="log"></div></body></html>留神:最下面有一个tim.js文件须要你自行创立,后续的教程都只对该文件进行变更阐明而已。 ...

May 30, 2022 · 7 min · jiezi

关于swoole:Swoole-定时器能实现毫秒级任务调度你敢相信吗

简介 Timer 毫秒精度的定时器,底层基于 epoll_wait 和 setitimer 实现,数据结构应用 最小堆 ,可反对增加大量定时器,应用最小堆数据结构实现的定时器,相似 JavaScript 的 setInterval,Swoole 定时器的增加和删除,全副为内存操作,因而性能是十分高的。 Swoole 中的 Timer 与 PHP 自身的 pcntl_alarm 是不同的。pcntl_alarm 是基于 时钟信号 + tick 函数实现,一个是最大仅反对到秒,另一个是不反对同时设定多个定时器程序,性能相对来说会比拟差。 距离时钟定时器 咱们能够通过 Timer::tick 来实现距离时钟定时器,定时器会继续触发,每隔指定工夫主动触发执行回调函数, 直到调用 Timer::clear 来革除指定的定时器。 $i = 0;Swoole\Timer::tick(1000, function($id) use ($i) { global $i; echo "tick id:$id i:$i \n"; $i++;});每隔 1 秒工夫触发一次回调函数,回调函数会主动打印一行信息到控制台。一次性定时器 须要执行一次定时器的时候能够应用 Timer::after , 此函数是一个一次性定时器,与距离时钟定时器不同,执行实现后就会销毁,须要留神的是 Timer::after 是非阻塞的。 Swoole\Timer::after(2000, function () { echo "执行一次的after\n";});2 秒后执行回调函数,执行实现后主动退出。革除定时器 Timer::after 执行实现后会主动退出,不须要革除,而 Timer::tick 没有革除定时器操作,会始终执行,直到程序退出。 当不须要定时器的时候,咱们能够应用 Timer::clear 来达到进行定时器的目标,将对应定时器 id 传入该办法即可。 ...

May 9, 2022 · 1 min · jiezi

关于swoole:Swoole中的协程使用相关说明快来围观

什么是协程 协程能够简略了解为线程,只不过这个线程是用户态的,不须要操作系统参加,创立销毁和切换的老本非常低,和线程不同的是协程没法利用多核 cpu 的,想利用多核 cpu 须要依赖 Swoole 的多过程模型。 协程特点开发者能够无感知的用同步的代码编写形式达到异步 IO 的成果和性能,防止了传统异步回调所带来的离散的代码逻辑和陷入多层回调中导致代码无奈保护。同时因为底层封装了协程,所以比照传统的 PHP 层协程框架,开发者不须要应用 yield 关键词来标识一个协程 IO 操作,所以不再须要对 yield 的语义进行深刻了解以及对每一级的调用都批改为 yield,这极大的进步了开发效率。协程适宜 IO 密集型利用,因为协程在 IO 阻塞 时会主动调度,缩小 IO 阻塞导致的工夫损失。睡眠 1 万次,读取,写入,检查和删除文件 1 万次,应用 PDO 和 MySQLi 与数据库通信 1 万次,创立 TCP 服务器和多个客户端互相通信 1 万次,创立 UDP 服务器和多个客户端到互相通信 1 万次...... 一切都在一个过程一秒内完满实现!实用场景 高并发服务,如秒杀零碎、高性能API接口、RPC服务器,连接池,IM聊天、游戏服务器、物联网、音讯服务器等。 示例1:用户能够通过go函数创立一个协程,以达到并发执行的成果,如上面代码所示: go(function () { echo "one" . PHP_EOL;});go(function () { echo "two" . PHP_EOL;});go(function () { echo "three" . PHP_EOL;});每当呈现一个go,底层会主动创立一个协程,协程输入内容后,而后主动退出示例2:通过协程能够并发执行客户端申请,应用到协程调度带来的 IO 阻塞时的调度,来实现高性能服务,上面是通过 defer 机制实现申请的并发执行: ...

April 26, 2022 · 1 min · jiezi

关于swoole:PHP-基于-SWX-框架搭建高性能API架构四

前言官网地址:SW-X框架-专一高性能便捷开发而生的PHP-SwooleX框架 心愿各大佬举起小手,给小弟一个star:https://github.com/swoolex/swoolex 1、什么是中间件中间件属于AOP切面编程的衍生,SW-X中的中间件能够通过绑定路由地址,实现控制器无切入的关联绑定。 在中间件中,能够进行申请拦挡(前置操作)、或者申请缓存销毁(后置操作)等业务。 2、通过路由绑定中间件接回上章案例,咱们当初要对/api/*前缀的所有接口,对立绑定一个名为Auth的中间件。 须要先再/config/middleware.php中间件配置文件中注册绑定规定: <?phpreturn [ // 匹配中间件,路由前半段是/api/结尾的都会绑定到 '/api/*' => [ \box\middleware\Auth::class, ],];所有中间件不强制继承\x\Middleware基类,但个别倡议继承,\x\Middleware类提供了一个error()办法,当开发者想中断利用持续向下执行时,能够调用该办法,抛出自定义的提醒内容到客户端,该办法兼容了框架中4种不同的服务。 中间件倡议(但不强制)对立寄存在/box/middleware目录下, 便于项目管理。 接下来,咱们在/box/middleware/目录下,创立一个Auth.php类,并写入代码: <?php/** * +---------------------------------------------------------------------- * 权限中间件 * +---------------------------------------------------------------------- * 官网:https://www.sw-x.cn * +---------------------------------------------------------------------- * 作者:小黄牛 <1731223728@qq.com> * +---------------------------------------------------------------------- * 开源协定:http://www.apache.org/licenses/LICENSE-2.0 * +----------------------------------------------------------------------*/namespace box\middleware;use x\Middleware;use x\Restful;class Auth extends Middleware{ // 须要跳过的路由 private $_skip = [ 'shop/delete', ]; // 须要跳过的前置路由 private $_group_skip = [ 'login/', ]; /** * 前置操作 * @todo 无 * @author 小黄牛 * @version v2.5.0 + 2021.07.20 * @deprecated 暂不启用 * @global 无 * @return void */ public function handle() { // 取得以后路由地址 $route = \x\Config::get('route'); $url = str_replace($route['suffix'], '', ltrim(\x\Request::url(), $route['cutting'])); $url = substr_replace($url, '', 0, (strpos($url, $route['cutting'])+1)); // 跳过校验 if (in_array($url, $this->_skip)) { return true; } // 跳过校验 foreach ($this->_group_skip as $v) { if (stripos($url, $v) === 0) { return true; } } // 通过上下文,取得申请实例 $Request = \x\context\Request::get(); $get = $Request->get;// get表单 $post = $Request->post;// post表单 $header = $Request->header;// post表单 // 没有拜访权限 if (!isset($get['test'])) { Restful::code(Restful::ACTION_ERROR())->callback(); // 返回false示意中断执行 return false; } // 返回true示意持续向下执行 return true; }}同时,因为下面咱们应用了一个ACTION_ERROR状态码,所以要在Restful状态码文件中退出响应的配置。 ...

March 2, 2022 · 2 min · jiezi

关于swoole:2022112thinkswoole使用教程

think-swoole应用教程核心思想是swoole只是作为一个音讯转发器,业务逻辑还是通过接口来实现,发送音讯也是应用接口,客户端websocket只负责创立和监听承受音讯即可。环境centos8PHP7.4thinkphp6.0.10think-swoole4.0.6开发过程装置think-swoole扩大为了不便咱们装置think-view扩大配置swoole.php文件 server.host 服务器IPserver.port 服务器端口server.options.daemonize 是否过程websocket.enable 关上websocketwebsocket.handle 本人接管或者应用默认(默认的会给咱们发送socket音讯,不理睬即可)websocket.subscribe 创立事件订阅,我这里的文件名是WebSocketEvent(也能够应用监听,只不过须要多个文件)因为是多过程,咱们须要共享变量,能够用MySQL、redis等,咱们这里应用swoole的共享内容Table,因为同一个用户可能是多端登录,咱们创立俩个Table,一个是用户映射fd,一个是fd映射用户,Table的映射是一对一的,然而一个用户可能有多个fd,所以用户映射fd的Table的值应用逗号分隔的多个值,例如用户1->fd1,fd2配置tables俩个table,别离是m2fd、fd2m,thinkphp实现的Table如何应用请本人看代码 'tables' => [ 'm2fd' => [ 'size' => 102400, 'columns' => [ ['name' => 'fd', 'type' => \Swoole\Table::TYPE_STRING, 'size' => 50] ] ], 'fd2m' => [ 'size' => 102400, 'columns' => [ ['name' => 'member_id', 'type' => \Swoole\Table::TYPE_INT] ] ],],通过订阅实现websocket逻辑把咱们须要应用的类通过构造函数依赖注入,方便使用咱们须要WebSocket类实现通信逻辑,Table类实现用户fd映射如果咱们应用了type为11的绑定形式,则订阅open事件,发送给客户端message事件办法体留空或者不写即可,咱们应用接口来实现逻辑close事件移除用户和fd的映射关系咱们定义一个事件,用于接口触发,从而实现发送音讯逻辑,事件名称叫做ApiEvent,代码如下 <?phpdeclare (strict_types = 1);namespace app\subscribe;use app\Request;use Swoole\Server;use think\swoole\Table;use think\swoole\Websocket;class WebSocketEvent{ private $websocket = null; private $m2fd = null; private $fd2m = null; public function __construct(Websocket $websocket, Table $table) { $this->websocket = $websocket; $this->m2fd = $table->get('m2fd'); $this->fd2m = $table->get('fd2m'); } // 这里之所以注入一个申请,是因为如果咱们不必type=11这种形式绑定,则能够通过new WebSocket的时候把用户ID传递过去,而后间接实现绑定 public function onOpen(Request $request) { $currentFd = $this->websocket->getSender(); $data = [ 'type' => 11, 'fd' => $currentFd ]; $this->websocket->push(json_encode($data)); } public function onClose() { $currentFd = $this->websocket->getSender(); // 通过fd找到用户ID $memberId = $this->fd2m->get((string)$currentFd, 'member_id'); // 如果没有找到映射,就阐明没有绑定过,就什么不做,找到的话就解除绑定 if ($memberId) { $this->fd2m->del((string)$currentFd); // 依据用户ID找到映射的所有fd,而后把存在的以后fd移除掉 $fds = $this->m2fd->get((string)$memberId, 'fd'); if ($fds) { $fdArray = explode(',', $fds); $key = array_search($currentFd, $fdArray); unset($fdArray[$key]); if ($fdArray) { $resFds = implode(',', $fdArray); $this->m2fd->set((string)$memberId, $resFds); } else { $this->m2fd->del((string)$memberId); } } } } public function onApiEvent($data) { // $data是接口传递过去的参数,如果是11则实现绑定,是5就转发给from_id和to_id if ($data['type'] == 11) { // m2fd、fd2m俩个Table的映射 $this->fd2m->set((string)$data['fd'], ['member_id' => $data['member_id']]); // 先查找该用户ID是否曾经绑定过其它fd了 $fds = $this->m2fd->get((string)$data['member_id'], 'fd'); if (!$fds) { $this->m2fd->set((string)$data['member_id'], ['fd' => $data['fd']]); } else { // 看看fd是否在曾经映射的fd中,如果在就什么都不做,如果不在就追加到前面 $fdArray = explode(',', $fds); if (!in_array($data['fd'], $fdArray)) { $this->m2fd->set((string)$data['member_id'], ['fd' => $fds . ',' . $data['fd']]); } } } if ($data['type'] == 1) { // 依据from_id和to_id俩个用户ID找到对应的fd,而后发送音讯 $fromFds = $this->m2fd->get((string)$data['from_id'], 'fd'); $toFds = $this->m2fd->get((string)$data['to_id'], 'fd'); $fromFdArray = $toFdArray = []; if ($fromFds) { $fromFdArray = explode(',', $fromFds); } if ($toFds) { $toFdArray = explode(',', $toFds); } // 合并所有发送者fd和接受者fd,之所以发送给发送者,一方面是简化前端工作,前端只须要承受websocket音讯即可,另一方面,多端的话其它端能够能够即时看到聊天记录 $allFdArray = array_unique(array_merge($fromFdArray, $toFdArray)); // 发送音讯 $this->websocket->to($allFdArray)->push(json_encode($data)); } }}接口实现代码如下 ...

January 12, 2022 · 3 min · jiezi

关于swoole:swoole客户端分析与讲解作为TCP链接webscoket链接等客户端

swoole客户端文章目录1.swoole客户端能解决什么样的问题?2.如何应用?3.注意事项1.首先明确swoole客户端能帮忙咱们解决什么样的问题?业务场景当业务中须要链接TCP,UDP,socket,websocket 服务时,咱们须要编写一个客户端去链接对应的服务(比方链接某些数据源)。 此时有很多种的抉择,workerman的AsyncTcpConnection,或者应用php自带的socket函数(socket_create,socket_read等函数),swoole的客户端(Swoole\Client)等都能够。各有优劣,抉择适宜本人和业务的就好,这次咱们抉择Swoole\Client。 2.如何应用?废话不多说,间接上我封装好的代码,看不懂多看正文了解,能够珍藏不便当前能够间接应用。 class SwooleClient{ //链接对象 private $client; /** * SwooleClient constructor. */ public function __construct() { $this->client = new Swoole\Client(SWOOLE_SOCK_TCP); $this->client->set(array( 'open_eof_check' => true, //关上EOF检测 'package_eof' => "\r\n", //设置EOF,包之间的分隔符 'package_max_length' => 1024 * 1024 * 2,//设置一个包的最大数据包尺寸,单位为字节。默认2m )); } /** * Notes: 链接对应的ip * User: 闻铃 * DateTime: 2021/11/17 下午10:46 * @param string $ip 链接的ip,本地或外网ip * @param int $port 端口号 * @throws \Exception */ public function connect($ip = '127.0.0.1', $port = 9501) { if (!$this->client->connect($ip, $port, -1)) { throw new \Exception(sprintf('Swoole Error: %s', $this->client->errCode)); } } /** * Notes: 发送数据 * User: 闻铃 * DateTime: 2021/11/17 下午10:44 * @param $data 发送的数据 * @return mixed * @throws \Exception */ public function send($data) { if ($this->client->isConnected()) { if (!is_string($data)) { $data = json_encode($data); } return $this->client->send($data); } else { throw new \Exception('Swoole Server does not connected.'); } } /** * Notes: 敞开链接 * User: 闻铃 * DateTime: 2021/11/17 下午10:45 */ public function close() { $this->client->close(); } /** * Notes: 接收数据 * User: 闻铃 * DateTime: 2021/11/17 下午10:45 * @return array */ public function recv() { //承受数据 return $this->client->recv(); }}如果想要作为webscoket客户端的话,也是能够的,能够应用官网的websocket包(saber)后续更新 ...

November 17, 2021 · 1 min · jiezi

关于swoole:swoole毫秒定时器讲解以及实战详细分析

本文分享一个本人应用swoole毫秒定时器遇过的坑,以及解决的办法。心愿能帮忙遇到大家。学习毫秒定时器前,须要具备应用的根底语法,请参考官网文档(https://wiki.swoole.com/#/timer),我就不照搬了。 其中应用毫秒定时器的注意事项要多留神一下,以防前面犯错都不晓得啥起因 1. 定时器仅在以后过程空间内无效2. 定时器是纯异步实现的,不能与同步 IO 的函数一起应用,否则定时器的执行工夫会产生错乱3. 定时器在执行的过程中可能存在肯定误差置信大家在看swoole的毫秒定时器时,跟着官网根底的例子都会写。但用到理论我的项目中,要怎么联合呢?上面就开始分享一下我本人在理论我的项目中应用swoole定时器的形式。 咱们以think5.1框架为例子,比方在某个控制器中,应用毫秒定时器依据官网文档,写出这么一个例子。 public function test(){ $param1 = 'aaa'; $path = __DIR__.'/demo.txt'; //每隔两秒往demo.txt文件写一次数据,用此例子代替业务逻辑 swoole_timer_tick(2000,function () use ($param1, $path) { file_put_contents($path,$param1.'|'.'1'.PHP_EOL,FILE_APPEND); });}你们感觉有问题吗? 马上运行看看 解说一下运行形式:咱们都晓得swoole运行在cli形式下,间接通过浏览器拜访这个办法,必定会报错。报swoole只能运行在cli形式下。那咱们要在cli下如何运行呢?在thinkphp中,咱们就能够在入口文件处,以上面的形式运行swoole。php index.php api/task/testapi/task/test tp中拜访形式:模块名/控制器名/办法名 发现报错.这个谬误我当初百度谷歌了半天,没搞懂。通过询问官网作者后,得以解决.须要在程序开端加这么一段代码 `public function test() { $param1 = 'aaa'; $path = __DIR__.'/demo.txt'; //每隔两秒往demo.txt文件写一次数据,用此例子代替业务逻辑 swoole_timer_tick(2000,function () use ($param1, $path) { file_put_contents($path,$param1.'|'.'1'.PHP_EOL,FILE_APPEND); }); \Swoole\Event::wait();}` 因为定时器是异步的,执行完定时器后,会持续往下执行,而上面没有代码程序就完结了。所以在加一个wait操作,使程序阻塞在那里。这样定时器在两秒后能力继续执行,不会报错。 联想:而在swoole\server的onWorkerStart办法中应用定时器,为啥不必加wait操作,是因为在server->start操作中,其实就加了wait操作。swoole底层解决了,让程序始终阻塞在start办法中。 加上后,再次运行 发现不报错了,查看文件也是有数据的,此时胜利了一大半了。 此时发现程序始终占用着终端。如果咱们ctrl + c,退出定时器就退出了,咱们的业务逻辑就不执行了,这时又来了一个问题,如果定时器能在变成守护过程,始终在后盾运行就好了。 如何变成后盾运行的形式呢?分享两个我的做法。 1.应用nohup命令(linux自带命令)。不挂断的执行某个命令 nohup /usr/local/php/bin/php index.php api/task/test >/dev/null 2>&1 &解释:在后盾不间断的运行命令(/usr/local/php/bin/php index.php api/task/test),并把运行中的输入重定向到linxu的/dev/null(黑洞文件),2>&1是标准化输入。 & 是nohup的命令要求。这样子,就能够把脚本变成守护过程运行了。如下图,就不会霸占光标当前台的形式始终运行了 ...

November 15, 2021 · 1 min · jiezi

关于swoole:swoole-是一个高性能网络通信框架

swoole 是一个高性能网络通信框架, 根本不必 Nginx了, 能够思考用Nginx 做代理服务器。 [ Hyperf、Swoft、EasySwoole、MixPHP ] Master 主过程负责创立多个线程来承受和返回用户的申请, 同时生成一个 manager 过程. manager 过程负责生成和治理 N 多个 worker 和 tasker 过程.worker 和 task 是负责干活的. Manager 项目经理 worker 组长 taskWker 组员 一、Swoole 解说 TCP 服务器UDP 服务器 HTTP 服务器 WebSocket 服务器 Task 工作 协程、管道等 二、异步IO 场景 swoole_timer_tick 毫秒级别定时器 异步文件IOSwoole\Coroutine\System::writeFile()Swoole\Coroutine\System::readFile($filename); 异步MySQL//此行代码后,文件操作,sleep,Mysqli,PDO,streams等都变成异步IO,见文档"一键协程化"章节Swoole\Runtime::enableCoroutine(); 异步Redis

September 30, 2021 · 1 min · jiezi

关于swoole:并行加速脚本任务编写总结协程

1、环境筹备php7/8+ swoole4.6+2、示例代码Coroutine\run(function () use ($db_work, $db_process) { $connPool = new PDOPool((new PDOConfig) ->withHost($db_work['host']) ->withPort(3306) // ->withUnixSocket('/tmp/mysql.sock') ->withDbName($db_work['database']) ->withCharset('utf8mb4') ->withUsername($db_work['user']) ->withPassword($db_work['password']) ); $processPool = new PDOPool((new PDOConfig) ->withHost($db_process['host']) ->withPort(3306) // ->withUnixSocket('/tmp/mysql.sock') ->withDbName($db_process['database']) ->withCharset('utf8mb4') ->withUsername($db_process['user']) ->withPassword($db_process['password']) ); $channel = new Channel(60); $conn = $connPool->get(); $data1 = $conn->query('SELECT count(*) FROM `goods_images` WHERE image_url!=\'\'')->fetchAll(PDO::FETCH_NUM); $data2 = $conn->query('SELECT count(*) FROM `goods_sku` WHERE original_img!=\'\' AND is_delete=0')->fetchAll(PDO::FETCH_NUM); $data3 = $conn->query('SELECT count(*) FROM `goods_spu` WHERE original_img!=\'\' AND is_delete=0')->fetchAll(PDO::FETCH_NUM); $connPool->put($conn); $goods_images_total = $data1[0][0]; $goods_sku_total = $data2[0][0]; $goods_spu_total = $data3[0][0]; $todo = [ 'goods_images' => $goods_images_total, 'goods_sku' => $goods_sku_total, 'goods_spu' => $goods_spu_total, ]; print_r($todo); Coroutine::create(function () use ($channel, $todo) { foreach ($todo as $table => $total) { $page = 0; //第一页开始 while ($page++ <= $total) { $channel->push(['page' => $page, 'table' => $table]); } } }); Coroutine::create(function () use ($channel, $connPool, $processPool) { while (1) { $data = $channel->pop(10); if ($data) { $page = $data['page']; $table = $data['table']; // todo echo($page . ' <== task执行结束 ok' . PHP_EOL); } else { if ($channel->isEmpty()) { echo 'images $channel:empty' . PHP_EOL; break; } } } });});a.剖析建设能够独立运行的最小单位cell两头异步瓶颈mysql也应用连接池,连接池容量应该大于协程工作池容量;应用mysql连接池留神“有借有还”,$conn = $connPool->get();$connPool->put($conn); ...

September 18, 2021 · 1 min · jiezi

关于swoole:TP6Swoole4-反向代理配置

Nginx反向代理配置首先配置反向代理前曾经要把之前配置过的伪动态删除掉,不然保留的时候报错以下是反向代理的残缺配置,请留神其中的端口号[8000]以后这个端口号就是config\swoole.php文件中的server.port配置中的端口号location ~* .(php|jsp|cgi|asp|aspx)${ proxy_pass http://127.0.0.1:8000; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header REMOTE-HOST $remote_addr;}location /{ proxy_pass http://127.0.0.1:8000; proxy_set_header Host $host;proxy_set_header X-Real-IP $remote_addr;proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;proxy_set_header REMOTE-HOST $remote_addr;add_header X-Cache $upstream_cache_status;#Set Nginx Cache add_header Cache-Control no-cache;expires 12h;}复制代码须要兼容wss和ws协定的可依照以下形式配置,只须要更换location /{}内的配置接口一兼容 应用宝塔部署我的项目的间接能够复制上面的代码来替换反向代理配置中location /{}地位的代码,改反向代理中的配置,别改错了;location /{ proxy_pass http://127.0.0.1:8000; proxy_http_version 1.1; proxy_read_timeout 360s; proxy_redirect off; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header REMOTE-HOST $remote_addr; add_header X-Cache $upstream_cache_status; #Set Nginx Cache add_header Cache-Control no-cache; expires 12h;}复制代码长连贯拜访地址 ...

September 10, 2021 · 1 min · jiezi

关于swoole:swoole协程复用提高性能

实现一个HTTP服务器时,每个申请开一个协程解决,解决完申请后销毁,让咱们优化这段逻辑,咱们很容易联想到FASTCGI比照CGI的改良。无非就是事后生成几个worker过程,解决实现后不销毁复用嘛。 那协程也是同理,为了不便演示,只开一个协程,便于了解。 一个申请一个协程: <?phpCo::set(['hook_flags'=> SWOOLE_HOOK_ALL]);use function Co\run;run(function () { $socket = stream_socket_server( 'tcp://0.0.0.0:9998', $errno, $errstr ); if (!$socket) { echo "$errstr ($errno)" . PHP_EOL; exit(1); } while (true) { $conn = stream_socket_accept($socket); if ($conn) { go(function() use ($conn) { fwrite($conn, "HTTP/1.1 200 OK\r\nContent-Length:11\r\n\r\nHello!world"); }); } }});协程复用: <?phpCo::set(['hook_flags'=> SWOOLE_HOOK_ALL]);use Co\Channel;use function Co\run;run(function () { $channel = new Channel(1); go(function() use ($channel) { while (($conn = $channel->pop()) !== false) { fwrite($conn, "HTTP/1.1 200 OK\r\nContent-Length:11\r\n\r\nHello!world"); } }); $socket = stream_socket_server( 'tcp://0.0.0.0:9999', $errno, $errstr ); if (!$socket) { echo "$errstr ($errno)" . PHP_EOL; exit(1); } while (true) { $conn = stream_socket_accept($socket); if ($conn) { $channel->push($conn); } }});事实中,咱们不会只开一个协程,下次有工夫再来撸一个协程池,实现getWorker和putWorker,反对协程池动静扩容。 ...

August 20, 2021 · 1 min · jiezi

关于swoole:-EasySwoole-发布-v346-部分组件更新-企业级分布式-PHP-协程框架

EasySwoole 公布 v3.4.6 局部组件更新更新内容此次更新咱们更新了局部组件的性能,并且修复局部组件的 bug,持续晋升了 EasySwoole 的稳定性。 公布组件 easyswoole/component v2.3.1 版本;公布组件 easyswoole/rpc v5.0.5 版本;公布组件 easyswoole/pay v1.3.0 版本;对于以上组件的具体应用,请查看 EasySwoole 官网文档。 修复修复 easyswoole/pay 组件,修复不兼容最新支付宝单笔转账接口的 bug。优化优化 easyswoole/component 组件,防止过程对象被反复注册的问题。优化 easyswoole/rpc 组件,让用户能够自定义配置 rpc 服务端应用的最大内存限度。对于 EasySwooleEasySwoole 是一款反对企业级分布式部署的协程 PHP 框架,它是一款常驻内存型的分布式 Swoole 框架,专为 API 而生,解脱传统 PHP 运行模式在过程唤起和文件加载上带来的性能损失,反对高并发、高可用,相比于其余的 Swoole 框架(例如 Hyperf、Swoft 等),EasySwoole 的并发能力更强。EasySwoole 高度封装了 Swoole Server 而仍旧维持 Swoole Server 原有个性,反对同时混合监听 HTTP、WebSocket、自定义 TCP、UDP 协定,并且领有丰盛的组件。例如 协程通用连接池、TP 格调的协程 ORM、协程微信 SDK、协程支付宝 SDK、协程 Kafka 客户端、协程 ElasticSearch 客户端、协程 Consul 客户端、协程 Redis 客户端、协程 Apollo 客户端、协程 NSQ 客户端、协程自定义队列、 协程 Memcached 客户端、协程视图引擎、JWT、协程 RPC、协程 SMTP 客户端、协程 HTTP/WebSocket 客户端、协程 Actor、Crontab 定时器、协程 Redis 连接池、协程 MySQL 连接池、协程上下文治理、IOC、雪花算法 Snowflake Id 生成器、协程 HTTP、TCP、UDP、WebSocket 服务端 、验证器、验证码、自定义过程、Tracker 链路追踪、Atomic限流器、Fast-Cache 缓存、注解及 API 文档主动生成、Policy 权限、Casbin 验证权限、主动生成代码、OAuth、协程 OSS/COS 客户端、Printer 易联云打印机 SDK、数据库迁徙、协程 Etcd 客户端 等诸多组件。让开发者以最低的学习老本和精力编写出多过程、可异步、高可用的应用服务。 ...

August 10, 2021 · 1 min · jiezi

关于swoole:MixPHP-V3-开发流程体验-Swoole-Workerman-FPM-CLIServer-多种运行模式介绍

MixPHP V3 公布后,因为自身反对超多的执行模式,用户可能无从下手,这里先大体介绍一下: CLI-Server: 适宜本机开发,零扩大依赖,Windows/MacOS 等全平台反对PHP-FPM: 适宜共享开发环境部署,同时适宜 admin 等治理后盾我的项目Swoole, Workerman: 适宜线上部署,依据须要抉择其一即可Swoole 的多种模式: Swoole 多进程同步: 适宜须要应用那些协程不反对的第三方库的我的项目,和 Workerman 统一Swoole 多过程协程: 适宜专一 mysql + redis 须要超高 io 性能的我的项目Swoole 单过程协程: 单过程协程就是 V2.2 版本那种 golang 格调协程,适宜开发 websocket简直反对 PHP 风行的全副执行模式,并且以上执行模式代码是无缝切换的,真正做到效率与性能并存。 请帮忙 Star 一下: https://github.com/mix-php/mixhttps://gitee.com/mix-php/mix首先创立一个骨架咱们以开发一个 API 我的项目为例,关上 MixPHP 的 开发文档 外面有 cli api web websocket grpc 我的项目的开发教程,V3 开始仓库底下的 README 就是开发文档,如果有不明确的能够加咱们的 官网QQ群 参加探讨。 首先创立一个骨架如果提醒短少 redis 等扩大反对,能够应用 --ignore-platform-reqs 临时疏忽依赖查看 composer create-project --prefer-dist --ignore-platform-reqs mix/api-skeleton api装置后目录构造如下: bin 目录是全副入口文件,不同文件对应的不同驱动模式routes 是路由配置文件public/index.php 是 FPM, CLI-Server 两种模式的入口文件shell/server.sh 是部署是治理过程 start|stop|restart├── README.md├── bin│   ├── cli.php│   ├── swoole.php│   ├── swooleco.php│   └── workerman.php├── composer.json├── composer.lock├── conf│   └── config.json├── public│   └── index.php├── routes│   └── index.php├── runtime├── shell│   └── server.sh├── src│   ├── Command│   ├── Container│   ├── Controller│   ├── Error.php│   ├── Middleware│   ├── Vega.php│   └── functions.php└── vendor应用 CLI-Server 零扩大依赖模式本机开发首先咱们查看一下 composer.json,与其余框架不同的是咱们举荐在本机开发阶段应用 composer run-script 启动程序,能够和 PhpStorm 的调试性能完满配合。 ...

August 10, 2021 · 2 min · jiezi

关于swoole:laravelswoole的扩展不兼容消息队列该怎么办

这段时间用laravel8+laravel-swoole做我的项目,可发现laravel-swoole的扩大不兼容音讯队列; 思来想去这咋办呢,这咋办呢.咋办那就本人写咯!还好thinkphp-swoole扩大曾经兼容了,那不就嘿嘿嘿! 间接上批改的思路和代码!开干! 一种是减少另外启动的命令或者在swoole启动的时候一起启动音讯队列进行生产,我这么懒的人一个命令能解决的,绝不写两命令. 首先重写swoole启动命令 <?phpnamespace crmeb\swoole\command;use Illuminate\Support\Arr;use Swoole\Process;use SwooleTW\Http\Server\Facades\Server;use SwooleTW\Http\Server\Manager;use crmeb\swoole\server\InteractsWithQueue;use crmeb\swoole\server\FileWatcher;use Swoole\Runtime;class HttpServerCommand extends \SwooleTW\Http\Commands\HttpServerCommand{ use InteractsWithQueue; /** * The name and signature of the console command. * * @var string */ protected $signature = 'crmeb:http {action : start|stop|restart|reload|infos}'; /** * Run swoole_http_server. */ protected function start() { if ($this->isRunning()) { $this->error('Failed! swoole_http_server process is already running.'); return; } $host = Arr::get($this->config, 'server.host'); $port = Arr::get($this->config, 'server.port'); $hotReloadEnabled = Arr::get($this->config, 'hot_reload.enabled'); $queueEnabled = Arr::get($this->config, 'queue.enabled'); $accessLogEnabled = Arr::get($this->config, 'server.access_log'); $coroutineEnable = Arr::get($this->config, 'coroutine.enable'); $this->info('Starting swoole http server...'); $this->info("Swoole http server started: <http://{$host}:{$port}>"); if ($this->isDaemon()) { $this->info( '> (You can run this command to ensure the ' . 'swoole_http_server process is running: ps aux|grep "swoole")' ); } $manager = $this->laravel->make(Manager::class); $server = $this->laravel->make(Server::class); if ($accessLogEnabled) { $this->registerAccessLog(); } //热更新重写 if ($hotReloadEnabled) { $manager->addProcess($this->getHotReloadProcessNow($server)); } //启动音讯队列进行生产 if ($queueEnabled) { $this->prepareQueue($manager); } if ($coroutineEnable) { Runtime::enableCoroutine(true, Arr::get($this->config, 'coroutine.flags', SWOOLE_HOOK_ALL)); } $manager->run(); } /** * @param Server $server * @return Process|void */ protected function getHotReloadProcessNow($server) { return new Process(function () use ($server) { $watcher = new FileWatcher( Arr::get($this->config, 'hot_reload.include', []), Arr::get($this->config, 'hot_reload.exclude', []), Arr::get($this->config, 'hot_reload.name', []) ); $watcher->watch(function () use ($server) { $server->reload(); }); }, false, 0, true); }}InteractsWithQueue 类 ...

July 30, 2021 · 4 min · jiezi

关于swoole:MixPHP-V3-增加了-PHPFPMCLIServer-的支持

MixPHP V3 主推 Swoole、WorkerMan 驱动,因为这两个平台性能强劲。然而大部分的 PHP 开发者都是开发 API, Web 的程序员,热更新可能是最大的刚性需要,因而我对 Vega 做了扩大,让 MixPHP 减少了 PHP-FPM、CLI-Server 的反对,开发环境能够应用这两种模式,线上部署时切换为性能更强劲的 Swoole、WorkerMan 驱动。 开箱难即用PHP 生态须要很多外设,当咱们开发时: Swoole:须要装置 swoole 扩大WorkerMan:win 不须要装置,macOS 须要装置 pcntl,线上部署须要装置 eventPHP-FPM: 须要装置 php-fpm, nginxCLI-Server:惟一不须要装置任何货色,间接在命令行启动,自带热更新PHP-FPM和 Laravel、ThinkPHP 部署办法完全一致,将 public/index.php 在 nginx 配置 rewrite 重写即可 实时热更新适宜在多人共享的开发环境中应用这种模式同时如果有些治理后盾开发须要 session 的也能够应用该模式如何在 MixPHP 中应用CLI-ServerCLI-Server 是 PHP 内置的Web服务器,因为是单进程同步,因而性能个别不能在线上应用,然而和 phpfpm 一样自带热更新。 实时热更新适宜在本机开发无需任何额定的扩大,所有平台兼容反对动态文件解决,无需装置 nginx, phpfpm 这些如何在 MixPHP 中应用CLI-Server 模式在 thinkphp 中也反对,然而 thinkphp 不反对动态文件解决,MixPHP 对 动态文件 也做了反对,不须要额定采纳 nginx 解决文件。

July 28, 2021 · 1 min · jiezi

关于swoole:试用-mixvega-mixdb-进行现代化的原生-PHP-开发

最近几年在 javascript、golang 生态中游走,发现很多 npm、go mod 的长处。最近回过头开发 MixPHP V3 ,发现 composer 其实始终都是一个十分优良的工具,然而 phper 们对 composer 的用法很多都不是很深刻,明天我就采纳 composer 手撸一个原生我的项目,帮忙大家了解现代化的原生 PHP 开发流程。 PHP 的开发者可能是所有语言里被惯坏的最厉害的,因为简直每个框架都提供了脚手架,像这样: composer create-project这个在 npm、go mod 是没有这个性能的,须要本人创立程序骨架,当然 npm 和 go 生态产生了本人的解决方案,就是 vue-cli 和 mixcli 这样的脚手架工具来负责创立。 创立一个我的项目和 npm init 、go mod init 一样,咱们应用 composer init 创立一个我的项目 mkdir hellocd hellocomposer init 交互式填写一些内容后,生成了 composer.json 文件 { "name": "liujian/hello", "type": "project", "autoload": { "psr-4": { "Liujian\\Hello\\": "src/" } }, "require": {}}这个文件是以 composer 库的规范创立的,必须要两级名称,这让我很蛋疼,所以我批改一下 { "name": "project/app", "type": "project", "autoload": { "psr-4": { "App\\": "src/" } }, "require": {}}抉择我须要应用的库和 node.js、go 生态一样,第二步就是寻找咱们须要的库,通常咱们的需要是写一个 API 服务,就须要一个 http server 库,一个 db 库就能够开始工作了。 ...

July 7, 2021 · 3 min · jiezi

关于swoole:Mix-Vega-发布-支持-SwooleWorkerMan-的-CLI-HTTP-网络框架

Mix VegaVega 是一个用 PHP 编写的 CLI HTTP 网络框架,反对 Swoole、WorkerMan OverviewVega 是 MixPHP V3+ 内置的最外围的组件 (可独立应用),参考golang gin mux 开发,它蕴含 Web 利用解决的大量性能 (数据库解决除外),包含:路由、渲染、参数获取、中间件、文件上传解决等;具备 CLI 模式下弱小的兼容性,同时反对 Swoole、WorkerMan, 并且反对 Swoole 的多种过程模型。 源码地址Star 一下不迷路,下次用的时候还能找到 https://github.com/mix-php/vegahttps://gitee.com/mix-php/vegaInstallation须要先装置 Swoole 或者 WorkerMancomposer require mix/vegaQuick startSwoole 多过程 (异步) 中应用 <?phprequire __DIR__ . '/vendor/autoload.php';$vega = new Mix\Vega\Engine();$vega->handleF('/hello', function (Mix\Vega\Context $ctx) { $ctx->string(200, 'hello, world!');})->methods('GET');$http = new Swoole\Http\Server('0.0.0.0', 9501);$http->on('Request', $vega->handler());$http->start();Swoole 单过程 (协程) 中应用 <?phprequire __DIR__ . '/vendor/autoload.php';Swoole\Coroutine\run(function () { $vega = new Mix\Vega\Engine(); $vega->handleF('/hello', function (Mix\Vega\Context $ctx) { $ctx->string(200, 'hello, world!'); })->methods('GET'); $server = new Swoole\Coroutine\Http\Server('127.0.0.1', 9502, false); $server->handle('/', $vega->handler()); $server->start();});WorkerMan 中应用 ...

June 29, 2021 · 3 min · jiezi

关于swoole:Mac-Silicon-M1-编译安装-PHP8-Swoole46-ARM64-全过程记录

最近搞了一台 M1 的 Mac mini 筹备用这个开发 mixphp v3 版本,之前尝试了几次没有编译胜利,明天再次尝试装置胜利了,网络上很多人的文章存在问题(可能是零碎环境不同),特此分享让后续的人闭坑。 面临的问题因为最新版本的 macOS Big Sur 即使敞开平安模式 /usr/lib 也无奈写入文件,因而导致 make install 无奈装置任何 php 扩大,因而想装 Swoole 只能自行编译装置 php 到 /usr/local 目录 % csrutil statusSystem Integrity Protection status: disabled.% mkdir /usr/lib/php/extensions/testmkdir: /usr/lib/php/extensions/test: Read-only file systemPHP Build因为 brew arm64 版本无奈应用,只能采纳 x64 版本装置了一些依赖,前面导致了很多问题,本想编译一个 x64 PHP+Swoole 在编译 x64 Swoole 的时候异样就没有持续了,转而钻研 arm64 PHP+Swoole arch -x86_64 brew install openssl zlib curl libjpeg libpng libxml2 gettext freetype pcre libiconv libzip参数中的门路都须要依据本人电脑所装置的理论门路替换 ...

June 24, 2021 · 2 min · jiezi

关于swoole:Swoole-v47-版本新特性预览之-onDisconnect-事件回调

在之前的版本中可能有这样一种状况,在 WebSocket 服务器中无奈在 close 事件回调中辨别该 fd 是否为 WebSocket 连贯,例如以下代码: //创立WebSocket Server对象,监听0.0.0.0:9501端口$ws = new Swoole\WebSocket\Server('0.0.0.0', 9501);//监听WebSocket连贯关上事件$ws->on('Open', function ($ws, $request) { $ws->push($request->fd, "hello, welcome\n");});//监听WebSocket音讯事件$ws->on('Message', function ($ws, $frame) { echo "Message: {$frame->data}\n"; $ws->push($frame->fd, "server: {$frame->data}");});//监听WebSocket连贯敞开事件$ws->on('Close', function ($ws, $fd) { echo "client-{$fd} is closed\n";});$ws->start();启动服务后,应用浏览器对127.0.0.1:9501发动申请,终端会失去输入: client-1 is closed[2021-05-24 16:58:08 *37715.1] NOTICE end (ERRNO 1005): session[1] is closed这样的输入并不能晓得这个$fd为1的连贯是否为 WebSocket 连贯。如果业务代码中存在间接应用该$fd去做一些逻辑解决是无用的,也有可能会产生有人歹意申请导致占用资源。 那么相熟 Swoole 开发的人就会想到能够减少判断:应用 getClientInfo 办法的websocket_status值来获取 WebSocket 连贯状态 当服务器是 WebSocket\Server 时, getClientInfo 会额定减少websocket_status信息,它有对应的 4 种状态,别离为 常量对应值阐明WEBSOCKET_STATUS_CONNECTION1连贯进入期待握手WEBSOCKET_STATUS_HANDSHAKE2正在握手WEBSOCKET_STATUS_ACTIVE3已握手胜利期待浏览器发送数据帧WEBSOCKET_STATUS_CLOSING4连贯正在进行敞开握手,行将敞开能够批改上述代码中的 onClose 回调: ...

May 31, 2021 · 1 min · jiezi

关于swoole:macOS-Big-Sur下pecl安装swoole报需要openssl库解决方法

macOS中pecl形式装置swoole报Enable openssl support, require openssl library谬误 首先确保装置了openssl库,能够通过brew list --formula | grep openssl查看是否曾经装置 而后装置的时候在提醒openssl是否启用,手动指定openssl目录即可 enable openssl support? [no] yes --with-openssl-dir=/usr/local/Cellar/openssl@1.1/1.1.1h/留神openssl@1.1前面的子目录,确保外面存在include目录存在,否则会报openssl/ssl.h file not found谬误

March 17, 2021 · 1 min · jiezi

关于swoole:利用-Swoole-的-Channel-测试-Websocket-异步服务器性能

环境应用 Docker: 在 docker 中搭建 swoole 运行环境 服务器端应用后面文章中的代码: 在 Swoole 中应用 WebSocket 服务端和客户端 测试程序代码: <?phpuse Swoole\Coroutine\Channel;use Swoole\Coroutine\Http\Client;use function Swoole\Coroutine\run;class Test{ protected $request; //总申请量 protected $requested = 0; protected $start_time; protected $channel; function __construct() { $this->request = 5000; $this->channel = new Channel($this->request); } public function run() { $this->start_time = microtime(true); $this->webSocket(); } protected function webSocket() { // 创立一个协程容器 run(function () { for ($i = 0; $i < $this->request; $i++) { // 开启一个协程 go(function() use ($i) { $cli = new Client('127.0.0.1', 8081); $cli->set(['websocket_mask' => false]); $ret = $cli->upgrade('/'); if ($ret) { $ret = $cli->push('1 Hello World'); $this->channel->push([$i => $cli->recv(1)]); } }); } $this->finish(); }); } protected function finish() { for ($i = 1; $i <= $this->request; $i++) { $this->channel->pop(); $this->requested++; } $cost_time = round(microtime(true) - $this->start_time, 4); echo "Request num:" . $this->request.PHP_EOL; echo "Success num:" . $this->requested.PHP_EOL; echo "Total time:" . $cost_time.PHP_EOL; echo "Request per second:" . intval($this->request / $cost_time).PHP_EOL; }}$test = new Test();$test->run();测试后果: ...

December 19, 2020 · 1 min · jiezi

关于swoole:Swoole安装问题

Swoole装置问题官网文档 -- https://wiki.swoole.com/wiki/page/1.html 官网谬误问题 -- https://wiki.swoole.com/wiki/page/438.html 一.装置问题: 编译问题 (1) 明天部署PHP多版本共存,遇到编译失败error,没有找到php-config,在编译装置swoole时,./configure须要一些参数,残缺如下: ./configure --with-php-config=/usr/local/php7/bin/php-config 后边门路请替换成本人的理论门路。 (2) make: * [php_swoole_cxx.lo] 谬误 1 在执行这一步时 谬误:./configure --with-php-config=/www/server/php/72/bin/php 指定的是php-config文件,而不是php文件 正确:./configure --with-php-config=/www/server/php/72/bin/php-config

December 18, 2020 · 1 min · jiezi

关于swoole:thinkswoole实战案例演示

官网文档thinkphp6文档https://www.kancloud.cn/manua...swoole文档https://wiki.swoole.com/#/ think-swoole文档https://www.kancloud.cn/manua... 装置composer require topthink/think-swoole命令行php think swoole [start|stop|reload|restart]服务启动当你在命令行php think swoole下执行实现之后就会启动一个HTTP Server,能够间接拜访以后的利用 'server' => [ 'host' => env('SWOOLE_HOST', '0.0.0.0'), // 监听地址 'port' => env('SWOOLE_PORT', 9501), // 监听端口 'mode' => SWOOLE_PROCESS, // 运行模式 默认为SWOOLE_PROCESS 'sock_type' => SWOOLE_SOCK_TCP, // sock type 默认为SWOOLE_SOCK_TCP 'options' => [ // 服务启动后,过程ID寄存文件 'pid_file' => runtime_path() . 'swoole.pid', // swoole 的日志文件 'log_file' => runtime_path() . 'swoole.log', // 守护过程模式设置 true 后盾运行 'daemonize' => false, // 设置启动的reactor线程数 'reactor_num' => swoole_cpu_num(), // 设置启动的worker过程数 'worker_num' => swoole_cpu_num(), //配置Task过程的数量 'task_worker_num' => swoole_cpu_num(), //开启动态文件申请解决,需配合document_root 'enable_static_handler' => true, //动态文件根目录 'document_root' => root_path('public'), // 设置最大数据包尺寸,单位字节 'package_max_length' => 20 * 1024 * 1024, //配置发送输入缓冲区内存尺寸 'buffer_output_size' => 10 * 1024 * 1024, //设置客户端连贯最大容许占用的内存数量 'socket_buffer_size' => 128 * 1024 * 1024, ],],热更新swoole服务器运行过程中php文件是常驻内存运行,这样就能够防止反复的读取磁盘,反复的解释编译php,以便达到最高的性能,所以批改代码须要重启服务 ...

October 23, 2020 · 5 min · jiezi

关于swoole:Swoole-456-支持零拷贝-JSON-或-PHP-反序列化

在最新的4.5.6开发分支中,底层减少了2个非凡的函数: swoole_substr_json_decodeswoole_substr_unserialize这里为什么要减少这两个函数呢?有这样一种场景。应用Swoole\Server实现RPC服务,在EOF协定或长度协定通信形式下,一个包可能有3局部组成。 $packet = $header + $body + $footer通常$header和$footer比拟小,而$body比拟大,$body可能会应用JSON或PHP序列化格局。如果要解析$body数据,那么就须要先进行substr失去$body的字符串格局数据,再进行json_decode和unserialize操作。 这会引起一次内存拷贝,$body_str = substr($packet, $header_length)的过程会创立一个长期字符串变量,再反序列化操作$body = json_decode($body_str)之后,这个变量就会被开释。 // 先进行 substr,这时会产生内存拷贝,从 $packet 复制数据到 $body_str$body_str = substr($packet, 4, strlen($packet) - 4 - 2);// 反序列化之后 $body_str 这块内存不再应用,会在函数退出时开释$body = json_decode($body_str, true);应用新增的两个函数就能够将substr和反序列化操作合二为一。缩小一次内存拷贝,从而进步性能。 $body = swoole_substr_json_decode($packet, $header_length);$body = swoole_substr_unserialize($packet, $header_length);压测<?phperror_reporting(E_ALL);$a['hello'] = base64_encode(random_bytes(1000));$a['world'] = 'hello';$a['int'] = rand(1, 999999);$a['list'] = ['a,', 'b', 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'];$val = serialize($a);$str = pack('N', strlen($val)).$val."rn";$n = 100000;$s = microtime(true);while($n--) { $l = strlen($str) - 6; // var_dump(unserialize(substr($str, 4, $l))); var_dump(swoole_substr_unserialize($str, 4, $l));}echo "cost: ".(microtime(true)-$s)."n";应用swoole_substr_unserialize与substr + unserialize相比,性能晋升了12% ...

October 22, 2020 · 1 min · jiezi

关于swoole:thinkswoole扩展实现在传统phpfpm环境调用rpc服务

https://github.com/top-think/think-swoole tp官网的think-swoole提供了一个rpc服务和客户端,然而他的rpc客户端只能在swoole的环境下运行 然而swoole官网是提供了同步客户端/swoole/client的,如果把框架的client更换成官网的同步client,应该就能实现在传统的fpm环境中调用swoole环境下的rp~~~~c。 <?phpnamespace appservice;use Exception;use Generator;use SwooleClient;use SwooleCoroutine;use thinkhelperArr;use thinkService;use thinkswooleexceptionRpcClientException;use thinkswoolePool;use thinkswoolerpcclientConnector;use thinkswoolerpcclientGateway;use thinkswoolerpcclientProxy;use thinkswoolerpcJsonParser;use thinkswoolerpcPacker;use Throwable;class SwooleRpcServiceLoad extends Service{ public $rpcServices = []; /** * 注册服务 * * @return mixed */ public function register() { if (php_sapi_name() == 'fpm-fcgi') { if (file_exists($rpc = $this->app->getBasePath() . 'rpc.php')) { $this->rpcServices = (array)include $rpc; } } } /** * 执行服务 * * @return mixed */ public function boot() { if (!empty($clients = config('swoole.rpc.client')) && $this->rpcServices) { try { foreach ($this->rpcServices as $name => $abstracts) { $parserClass = config("swoole.rpc.client.{$name}.parser", JsonParser::class); $parser = $this->app->make($parserClass); $gateway = new Gateway($this->createRpcConnector($name), $parser); foreach ($abstracts as $abstract) { $this->app->bind($abstract, function () use ($gateway, $name, $abstract) { return $this->app->invokeClass(Proxy::getClassName($name, $abstract), [$gateway]); }); } } } catch (Exception | Throwable $e) { } } } protected function createRpcConnector($name) { return new class($name) implements Connector { public $name; public function __construct($name) { $this->name = $name; } public function sendAndRecv($data) { if (!$data instanceof Generator) { $data = [$data]; } $config = config('swoole.rpc.client.' . $this->name); $client = new Client(SWOOLE_SOCK_TCP); $host = Arr::pull($config, 'host'); $port = Arr::pull($config, 'port'); $timeout = Arr::pull($config, 'timeout', 5); $client->set([ 'open_length_check' => true, 'package_length_type' => Packer::HEADER_PACK, 'package_length_offset' => 0, 'package_body_offset' => 8, ]); $client->connect($host, $port, $timeout); try { foreach ($data as $string) { if (!$client->send($string)) { $this->onError($client); } } $response = $client->recv(); if ($response === false || empty($response)) { $this->onError($client); } return $response; } finally { $client->close(); } } protected function onError(Client $client) { $client->close(); throw new RpcClientException(swoole_strerror($client->errCode), $client->errCode); } }; }}把下面这个服务在thinkphp框架中注册,就能够实现在fpm环境下调用think-swoole的rpc ...

October 17, 2020 · 2 min · jiezi

关于swoole:Swoole-v455-版本发布增加配置项检测

此版本减少了配置项检测性能,如果设置了不是 Swoole 提供的选项,会产生一个 Warning。 PHP Warning: unsupported option [foo] in @swoole-src/library/core/Server/Helper.php$http = new Swoole\Http\Server('0.0.0.0', 9501);$http->set(['foo' => 'bar']);$http->on('request', function ($request, $response) { $response->header("Content-Type", "text/html; charset=utf-8"); $response->end("<h1>Hello Swoole. #".rand(1000, 9999)."</h1>");});$http->start();新增 API减少 Process\Manager,批改 Process\ProcessManager 为别名 (swoole/library#eac1ac5) (@matyhtf)反对 HTTP2 服务器 GOAWAY (#3710) (@doubaokun)减少 Co\map()函数 (swoole/library#57) (@leocavalcante)加强反对 http2 unix socket 客户端 (#3668) (@sy-records)当 worker 过程退出之后设置 worker 过程状态为 SW_WORKER_EXIT (#3724) (@matyhtf)在 Server::getClientInfo()的返回值中减少 send_queued_bytes 和 recv_queued_bytes (#3721) (#3731) (@matyhtf) (@Yurunsoft)Server 反对 stats_file 配置选项 (#3725) (@matyhtf) (@Yurunsoft)修复修复 PHP8 下的编译问题 (zend_compile_string change) (#3670) (@twose)修复 PHP8 下的编译问题 (ext/sockets compatibility) (#3684) (@twose)修复 PHP8 下的编译问题 (php_url_encode_hash_ex change) (#3713) (@remicollet)修复从'const char' to 'char'的谬误类型转化 (#3686) (@remicollet)修复 HTTP2 client 在 HTTP proxy 下无奈工作的问题 (#3677) (@matyhtf) (@twose)修复 PDO 断线重连时数据凌乱的问题 (swoole/library#54) (@sy-records)修复 UDP Server 应用 ipv6 时端口解析谬误修复 Lock::lockwait 超时有效的问题 ...

October 15, 2020 · 1 min · jiezi

关于swoole:Swoole-455-对-Server-数据收发时间的优化

Commit: https://github.com/swoole/swoole-src/pull/3708/files 在之前的版本中,底层提供了connect_time和last_time两项工夫信息,单位为秒,示意: 连贯到服务器的工夫最初一次接收数据的工夫在非常复杂理论的我的项目中,这两项信息是远远不能满足需要的,在最新的版本中咱们进行了优化。 工夫精度调整底层的工夫全副改为应用 double 类型,准确到了微秒,包含:建设连贯与数据接管、投递、数据。 减少发送和投递工夫在 Server::getClientInfo() 办法的返回值中减少了3个新的工夫字段,精度为微秒: last_recv_time:最近一次接收数据的工夫last_dispatch_time:最近一次投递数据的工夫,当触发onReceive回调时,读取此信息能够失去,以后的$data在master过程是什么工夫dispatch的,通过判断投递工夫和以后工夫的差值,能够失去工作在管道中期待的耗时last_send_time:最近一次发送到内核Socket缓存区的工夫,通过此工夫能够判断出客户端是否能够失常接管数据包,是否存在接管延时通过更准确的工夫数据,能够实现更细粒度的通信治理。

September 29, 2020 · 1 min · jiezi

关于swoole:Swoole-v453-版本发布

新增 API减少 Swoole\Process\ProcessManager (swoole/library#88f147b) (@huanghantao)减少 ArrayObject::append, StringObject::equals (swoole/library#f28556f) (@matyhtf)减少 Coroutine::parallel (swoole/library#6aa89a9) (@matyhtf)减少 CoroutineBarrier (swoole/library#2988b2a) (@matyhtf)加强减少 usePipelineRead 来反对 http2 client streaming (#3354) (@twose)http 客户端下载文件时,在承受数据前不创立文件 (#3381) (@twose)http client 反对bind_address和bind_port配置 (#3390) (@huanghantao)http client 反对lowercase_header配置 (#3399) (@matyhtf)Swoole\Server反对tcp_user_timeout配置 (#3404) (@huanghantao)Coroutine\Socket减少 event barrier 来缩小协程切换 (#3409) (@matyhtf)为特定的 swString 减少memory allocator (#3418) (@matyhtf)cURL 反对__toString (swoole/library#38) (@twose)反对间接在 WaitGroup 构造函数中设置wait count (swoole/library#2fb228b8) (@matyhtf)减少CURLOPT_REDIR_PROTOCOLS (swoole/library#46) (@sy-records)http1.1 server 反对 trailer (#3485) (@huanghantao)协程 sleep 工夫小于 1ms 将会 yield 以后协程 (#3487) (@Yurunsoft)http static handler 反对软连贯的文件 (#3569) (@LeiZhang-Hunter)在 Server 调用完 close 办法之后立即敞开 WebSocket 连贯 (#3570) (@matyhtf)反对 hook stream_set_blocking (#3585) (@Yurunsoft)异步 HTTP2 server 反对流控 (#3486) (@huanghantao) (@matyhtf)开释 socket buffer 在 onPackage 回调函数执行完 (#3551) (@huanghantao) (@matyhtf)修复修复 WebSocket coredump, 解决协定谬误的状态 (#3359) (@twose)修复 swSignalfd_setup 函数以及 wait_signal 函数里的空指针谬误 (#3360) (@twose)修复在设置了 dispatch_func 时候,调用Swoole\Server::close会报错的问题 (#3365) (@twose)修复Swoole\Redis\Server::format函数中 format_buffer 初始化问题 (#3369) (@matyhtf) (@twose)修复 MacOS 上无奈获取 mac 地址的问题 (#3372) (@twose)修复 MySQL 测试用例 (#3374) (@qiqizjl)修复多处 PHP8 兼容性问题 (#3384) (#3458) (#3578) (#3598) (@twose)修复 hook 的 socket write 中失落了 php_error_docref, timeout_event 和返回值问题 (#3383) (@twose)修复异步 Server 无奈在WorkerStart回调函数中敞开 Server 的问题 (#3382) (@huanghantao)修复心跳线程在操作 conn->socket 的时候,可能会产生 coredump 的问题 (#3396) (@huanghantao)修复 send_yield 的逻辑问题 (#3397) (@twose) (@matyhtf)修复 Cygwin64 上的编译问题 (#3400) (@twose)修复 WebSocket finish 属性有效的问题 (#3410) (@matyhtf)修复脱漏的 MySQL transaction 谬误状态 (#3429) (@twose)修复 hook 后的stream_select与 hook 之前返回值行为不统一的问题 (#3440) (@Yurunsoft)修复应用Coroutine\System来创立子过程时失落SIGCHLD信号的问题 (#3446) (@huanghantao)修复sendwait不反对 SSL 的问题 (#3459) (@huanghantao)修复ArrayObject和StringObject的若干问题 (swoole/library#44) (@matyhtf)修复 mysqli 打印谬误音讯时错别字的问题 (swoole/library#45) (@sy-records)修复当设置open_eof_check后,Swoole\Client无奈获取正确的errCode的问题 (#3478) (@huanghantao)修复 MacOS 上 atomic->wait()/wakeup()的若干问题 (#3476) (@Yurunsoft)修复Client::connect连贯回绝的时候,返回胜利状态的问题 (#3484) (@matyhtf)修复 alpine 环境下 nullptr_t 没有被申明的问题 (#3488) (@limingxinleo)修复 HTTP Client 下载文件的时候,double-free 的问题 (#3489) (@Yurunsoft)修复Server被销毁时候,Server\Port没开释导致的内存透露问题 (#3507) (@twose)修复 MQTT 协定解析问题 (318e33a) (84d8214) (80327b3) (efe6c63) (@GXhua) (@sy-records)修复Coroutine\Http\Client->getHeaderOut办法导致的 coredump 问题 (#3534) (@matyhtf)修复 SSL 验证失败后,失落了错误信息的问题 (#3535) (@twose)修复 README 中,Swoole benchmark链接谬误的问题 (#3536) (@sy-records) (@santalex)修复在HTTP header/cookie中应用CRLF后导致的header注入问题 (#3539) (#3541) (#3545) (chromium1337) (@huanghantao)修复 issue #3463 中提到的变量谬误的问题 (#3547) (chromium1337) (@huanghantao)修复 pr #3463 中提到的错别字问题 (#3547) (@deminy)修复协程 WebSocket 服务器 frame->fd 为空的问题 (#3549) (@huanghantao)修复心跳线程错误判断连贯状态导致的连贯透露问题 (#3534) (@matyhtf)修复Process\Pool中阻塞了信号的问题 (#3582) (@huanghantao) (@matyhtf)修复SAPI中应用 send headers 的问题 (#3571) (@twose) (@sshymko)修复CURL执行失败的时候,设置了谬误的code和message的问题 (swoole/library#1b6c65e) (@sy-records)修复当调用了setProtocol办法后,swoole_socket_coroaccept coredump 的问题 (#3591) (@matyhtf)内核应用 C++格调 (#3349) (#3351) (#3454) (#3479) (#3490) (@huanghantao) (@matyhtf)减少Swoole known strings来进步PHP对象读属性的性能 (#3363) (@huanghantao)多处代码优化 (#3350) (#3356) (#3357) (#3423) (#3426) (#3461) (#3463) (#3472) (#3557) (#3583) (@huanghantao) (@twose) (@matyhtf)多处测试代码的优化 (#3416) (#3481) (#3558) (@matyhtf)简化Swoole\Table的int类型 (#3407) (@matyhtf)减少sw_memset_zero,并且替换bzero函数 (#3419) (@CismonX)优化日志模块 (#3432) (@matyhtf)多处 libswoole 重构 (#3448) (#3473) (#3475) (#3492) (#3494) (#3497) (#3498) (#3526) (@matyhtf)多处头文件引入重构 (#3457) (@matyhtf) (@huanghantao)减少Channel::count()和Channel::get_bytes() (f001581) (@matyhtf)减少scope guard (#3504) (@huanghantao)减少 libswoole 覆盖率测试 (#3431) (@huanghantao)减少 lib-swoole/ext-swoole MacOS 环境的测试 (#3521) (@huanghantao)减少 lib-swoole/ext-swoole Alpine 环境的测试 (#3537) (@limingxinleo) ...

September 2, 2020 · 2 min · jiezi

关于swoole:基于PHP-swoole扩展的秒杀思路

基于PHP swoole扩大的秒杀思路通过ab压力测试,脚本QPS平均值在4500ab -n1000 -c10 http://127.0.0.1:9501/skill脚本代码,思路基本上也在代码正文中说明确了application-Index.php/** * 通过swoole的chan和协程解决秒杀 * 思路 * 设置一个通道channel数量为1,一个协程向外面写入用户的数据比方是用户的ID * 另一个协程来解决通道的数据写入beanstalkd或者Redis中的队列 * 此例子我选用写入Redis的list,因为我本机没装置beanstalkd */ public function skill() { $chan = new channel(1); $redis = new \Redis(); $redis->connect('127.0.0.1', 6379); $res = []; //生成者协程 co::create(function () use ($chan, $redis, &$res) { //查看chan中的数量 $num = $chan->length(); //当数量等于0并且库存还有的状况下的时候表名,通道为空能够写入数据 // stock库存须要提前设置到Redis if ($num == 0 && $redis->get('stock')) { $chan->push(['id' => rand(100, 999)]); } $res = [0, "抢购失败"]; }); //消费者协程 co::create(function () use ($chan, $redis, &$res) { $data = $chan->pop(); if ($data) { //此处默认每个人抢购1件,如果须要抢购多件能够在data中携带购买数量 //并写入到通道外面 $redis->set('stock', $redis->get('stock') - 1); //写入Redis list 其余脚本进行订单解决之类的IO业务。此处不实现了 $redis->lPush("skill_swoole", json_encode($data)); $res = [1, "抢购胜利"]; } }); return Tool::print_json($res[0], $res[1]); }代码仓库https://github.com/SmallForest/Thomas.kj这是自己本人写的框架,CLI模式,常驻内存性能高,感兴趣的能够提提倡议,帮忙一起优化。感激star ...

August 6, 2020 · 1 min · jiezi

关于swoole:PHP-框架-QueryPHP-10-正式版四年打磨生产可用

【开源新闻】https://www.oschina.net/news/... 明天是一个十分非凡的日期,在这里咱们将向大家发表一个重要的音讯,齐全重写的 QueryPHP 1.0 正式版公布了! 对于 QueryPHP QueryPHP 是一款现代化的高性能 PHP 渐进式协程框架, 咱们还是次要面向传统 PHP-FPM 场景,以工程师用户体验为历史使命,让每一个 PHP 利用都有一个好框架。 百分之百单元测试笼罩直面 Bug,致力于发明高品质产品 Level Level Leevel,依靠 Swoole 开启将来更多可能,此刻将来逐渐渐进。 咱们的愿景是USE LEEVEL WITH SWOOLE DO BETTER, 让您的业务撑起更多的用户服务。 https://github.com/hunzhiwange/queryphphttps://gitee.com/dyhb/queryphphttps://www.queryphp.com个性 Production-Ready (生产可用)框架理念 (值得托付的使命感,让每一个 PHP 利用都有一个好框架。)组件零碎 (框架底层由独立的高内聚低耦合组件形成,能够轻松无侵入接入现有零碎。)路由零碎 (框架提供 MVC 主动路由并可能智能解析 Restful 申请和基于 OpenApi 3.0 标准的 swagger-php 注解路由,文档路由一步搞定。)整体解决方案 (框架提供了从缓存、Session、IOC 容器、模板引擎、Ddd ORM 等大量开箱即用的性能,提供了基于 Symfony Console 命令行工具集。)高品质 (百分之百单元测试笼罩直面 Bug,致力于发明高品质产品 Level Level Leevel。)业务协程化 (基于 Swoole 4 开发,咱们的愿景是大量代码或者无批改,让你的业务撑起更多的用户服务。)百分之百单元测试笼罩(超过 3500 例测试用例保障系统可靠性和可继续保护。)PHP 7 严格模式 (每一个 PHP 脚本都是 strict_types=1,严格模式能够防止很多弱类型带来潜在 BUG。)PHP 7 类型提醒 (尽可能为每一个办法提供确定的参数类型和返回值类型,以及类属性的类型反对。)依赖注入(残缺实现,要害 MVC、命令行脚本、事件监听器全副接入 IOC 容器。)畛域驱动设计(反对 UnitOfWork 事务工作单元、Repository 仓储、Specification 查问规约,Entity Getter Setter 畛域实体等。)防止闭门造车 (QueryPHP 始终从 Laravel、Symfony 等框架排汇一些优良的设计,同时咱们本身也进行了大量的翻新设计。)更多的个性期待你的发现...缘起 ...

July 24, 2020 · 2 min · jiezi

关于swoole:PHP73Swoole44-Go113-MixPHP22-性能对比

好几年没有做过性能比照了,因为越来越感觉性能并没有那么的重要(绝对于生态),明天有工夫简略测试一下,因为 Mix v2.1 开始就全副切换为单过程协程模式,因而本次次要测试的是 CoHttpServer 。 环境CPU: Intel(R) Core(TM) i7-8700 CPU @ 3.20GHzCPU(s): 12Mem: 15GLinux version 3.10.0-957.10.1.el7.x86_64PHP 7.3.12 + Swoole 4.4.14代码中应用的单过程 CoHttpServer ,因而须要利用端口复用 (须要 Linux >= 3.10),开启 12 个过程 代码<?php \Swoole\Process::daemon();$scheduler = new \Swoole\Coroutine\Scheduler;$scheduler->set([ 'hook_flags' => SWOOLE_HOOK_ALL,]);$scheduler->add(function () { $server = new \Swoole\Coroutine\Http\Server('0.0.0.0', 8888, false, true); $server->handle('/', function($request, $response){ $response->end('hello, world!'); }); $server->start();});$scheduler->start();开启的过程[nobody@tmp]$ ps -ef | grep test.phpnobody 1917 1 0 20:22 ? 00:00:02 /usr/local/php-7.3.12/bin/php test.phpnobody 1923 1 0 20:22 ? 00:00:02 /usr/local/php-7.3.12/bin/php test.phpnobody 1929 1 0 20:22 ? 00:00:02 /usr/local/php-7.3.12/bin/php test.phpnobody 1934 1 0 20:22 ? 00:00:02 /usr/local/php-7.3.12/bin/php test.phpnobody 2154 1 0 20:22 ? 00:00:02 /usr/local/php-7.3.12/bin/php test.phpnobody 2166 1 0 20:22 ? 00:00:02 /usr/local/php-7.3.12/bin/php test.phpnobody 2173 1 0 20:22 ? 00:00:02 /usr/local/php-7.3.12/bin/php test.phpnobody 2181 1 0 20:22 ? 00:00:02 /usr/local/php-7.3.12/bin/php test.phpnobody 2187 1 0 20:22 ? 00:00:02 /usr/local/php-7.3.12/bin/php test.phpnobody 2194 1 0 20:22 ? 00:00:02 /usr/local/php-7.3.12/bin/php test.phpnobody 2200 1 0 20:22 ? 00:00:02 /usr/local/php-7.3.12/bin/php test.phpnobody 2205 1 0 20:22 ? 00:00:02 /usr/local/php-7.3.12/bin/php test.php测试:多跑几次,根本稳固在 127441.95 左右。[nobody@~]$ ab -n 100000 -c 1000 -k http://127.0.0.1:8888/This is ApacheBench, Version 2.3 <$Revision: 1430300 $>Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/Licensed to The Apache Software Foundation, http://www.apache.org/Benchmarking 127.0.0.1 (be patient)Completed 10000 requestsCompleted 20000 requestsCompleted 30000 requestsCompleted 40000 requestsCompleted 50000 requestsCompleted 60000 requestsCompleted 70000 requestsCompleted 80000 requestsCompleted 90000 requestsCompleted 100000 requestsFinished 100000 requestsServer Software: swoole-http-serverServer Hostname: 127.0.0.1Server Port: 8888Document Path: /Document Length: 13 bytesConcurrency Level: 1000Time taken for tests: 0.785 secondsComplete requests: 100000Failed requests: 0Write errors: 0Keep-Alive requests: 100000Total transferred: 16600000 bytesHTML transferred: 1300000 bytesRequests per second: 127441.95 [#/sec] (mean)Time per request: 7.847 [ms] (mean)Time per request: 0.008 [ms] (mean, across all concurrent requests)Transfer rate: 20659.53 [Kbytes/sec] receivedConnection Times (ms) min mean[+/-sd] median maxConnect: 0 0 2.4 0 47Processing: 2 7 0.5 7 47Waiting: 0 7 0.4 7 14Total: 2 8 2.6 7 58Percentage of the requests served within a certain time (ms) 50% 7 66% 7 75% 7 80% 7 90% 8 95% 8 98% 8 99% 18 100% 58 (longest request)Go 1.13.4Golang 默认应用全副 CPU 核,因而只需开启一个过程即可。 ...

July 22, 2020 · 6 min · jiezi

Swoole高并发聚合请求实例

一、前言本文旨在阐明在高并发场景下如何通过聚合申请,充分利用数据库的批量解决更高效地实现业务性能。当然,此示例仅用作抛砖引玉,心愿能激发读者更深刻的思考。二、注释本示例选取的背景是并发下单业务。惯例状况下,后端创立订单是逐条 insert 的操作。在并发较低的时候,数据库的 insert 操作确实能放弃不错的效率,然而当遇到申请数量增多,数据库 频繁地单次 insert 就会让下单业务整体效率变低 (本文简略地假如1次下单=1个 insert)。通过下面的形容,其实曾经很容易想到须要优化的中央了。类比现实生活中乘坐电梯的场景:一架电梯 装满后再上行,能够最快地缓解人流压力。上面咱们就来用代码简略实现一下咱们思路:<?phpSwoole\Runtime::enableCoroutine($flags = SWOOLE_HOOK_ALL);// 最大期待次数const MAX_TIMES = 10;// 按批处理时, 每一批的最大申请暂留数量const MAX_REQUEST = 3;// 服务端最大超时工夫, 防止客户端始终期待const MAX_TIMEOUT = 5;Co\run(function () { // 申请传输的channel, 起因是不要在swoole的协程环境中, 应用多个协程批改同一个全局变量 // 如果是golang, 当然是能够不定义这里的$rqChannel // 只须要简略的将上面的$rqQueue和$times定义为全局变量即可达到一样的成果 // 然而最好的形式任然是是通过channel共享内存 $rqChannel = new Swoole\Coroutine\Channel(MAX_REQUEST); // 模仿创立订单 $createOrder = function () use ($rqChannel) { // 应用数组模仿申请暂留队列 $rqQueue = []; // 应用期待次数模仿tick成果 $times = MAX_TIMES; while (true) { $times--; // 必须带上timeout参数, 否则channel是阻塞的 $rq = $rqChannel->pop(1); // 保留1个失常的申请数据 if (!empty($rq)) { $rqQueue[] = $rq; } // 申请数量未达下限或者还有期待次数时, 提前进入下一次循环 if ($times > 0 && count($rqQueue) < MAX_REQUEST) { continue; } // 重置期待次数 $times = MAX_TIMES; // 初始化SQL $sql = "INSERT INTO orders VALUES "; $inserts = []; // 模仿数据验证 $validator = function ($input): bool { // 为了缩减代码, 没有真的做数据验证的解决 array_filter($input); return true; }; // $rqQueue在协程上下文是并发平安的, 所以遍历时不必放心 foreach ($rqQueue as $index => $rq) { list($data, $chan) = $rq; // 这里能够思考后置执行, 起因是前面能够有一些补救逻辑 unset($rqQueue[$index]); // 判断$chan是否敞开å if ($chan->errCode === SWOOLE_CHANNEL_CLOSED) { $data = null; continue; } $bool = $validator($data); if ($bool) { $inserts[] = "({$data['user_name']}, {$data['amount']}, {$data['mobile']})"; $chan->push(['state' => 1]); } else { $chan->push(['state' => 0]); } // unset($rqQueue[$index]); } $sql .= (implode(',', $inserts) . ';'); // 模仿创立订单落库的逻辑 echo $sql; } }; // 老手要留神这一句代码的地位, 起因是 $server->start() 之后的代码不会执行 go($createOrder); // 路由处理器 $orderHandler = function ($rq, $res) use ($rqChannel) { $chan = new Swoole\Coroutine\Channel(1); // 应用timeout参数模仿超时 $bool = $rqChannel->push([$rq->post, $chan], MAX_TIMEOUT); if (!$bool) { // 敞开$chan $chan->close(); $res->end('timeout'); } if (!empty($data = $chan->pop())) { // 敞开$chan $chan->close(); // 辨别胜利或失败状态再输入响应 if ($data['state'] === 1) { $res->end(microtime()); } else { $res->end('error'); } } }; $server = new Co\Http\Server("0.0.0.0", 9502, false); $server->handle('/order/create', $orderHandler); // 以后协程容器的起点 $server->start();});代码整体上还是很容易了解的,变量 $rqQueue 就是类比电梯,暂留申请期待肯定工夫的次数 $times 就是类比电梯须要期待人流顺次进入。当然最在心愿读者留神的一点是:在协程环境下,不要应用共享内存而通信,应该应用通信来共享内存。三、结语本教程面向老手,更多教程会在日后给出。欢送分割在下,探讨倡议都能够,之后会公布其它的教程。

July 13, 2020 · 2 min · jiezi

Swoole-内核开发备忘内存管理优化swString

最新的优化,减少了从recv_buffer到php zval的内存copy,可以从recv_buffer变为PHP层的string类型变量,相当于直接从Socket接收缓存区中读取到了PHP层。 GitHub PR:https://github.com/swoole/swoole-src/pull/3423swString 结构体typedef struct _swString{ size_t length; size_t size; off_t offset; char *str; const swAllocator *allocator;} swString;在设计上,这几个字段的作用分别是: size:内存容量长度,进行append写入操作时,如果有空余的空间,无需扩容。当实际数据长度等于size时,需要进行内存扩容,通过调用swString_extend()完成length:实际数据长度,必须小于或等于size否则会内存越界,底层的swString_*系列函数会检查边界,避免越界读写offset:操作游标,记录应用层实际处理数据的位置,offset必须小于或等于length 新增了 allocator 字段,可以设置内存分配器,目前有3种。 SwooleG.std_allocator:标准的glibc mallocSWOOLE_G(php_allocator):PHP 的 emallocSWOOLE_G(zend_string_allocator):zend_string_alloc数据处理coroutine::Socket::recv_packet() 分为两个阶段从Socket中读取数据。 读取PacketHeader数据,可能是一个比较小的值,如 recv(sizeof(PacketHeader)),在头部中包含PacketLength字段,获取整个包的总长度读取Payload数据,recv(PacketLength - sizeof(PacketHeader)底层会预先将offset值设置为PacketLength,然后分段从网络收取数据,调用recv操作,将数据追加到缓存区,并更新length值。当length==offset时表示,接收完毕。coroutine::Socket::recv_packet()返回到应用层。这时应用层可以有两个操作。 使用memcpy将数据从recv_buffer中读取出来,下一次调用recv_packet时,底层会自动调用swString_reduce()重置recv_buffer缓存区,这会存在一次内存拷贝,但是复用一块内存的使用swString_pop()将recv_buffer->str整块内存弹出,在应用层使用,底层会自动分配新的内存,用于接收下一个包本次的 zerocopy 就是使用第二种方式,recv_buffer 使用了 SWOOLE_G(zend_string_allocator) 内存分配器,弹出来的 recv_buffer->str 内存,正好是一个 zend_string 的val,再使用 sw_get_zend_string(recv_buffer->str) 就可以得到 zend_string 对象的内存地址,最后使用 ZVAL_STR() 或者 RETURN_STR() 可直接将 zend_string 对象作为 PHP 层函数调用的返回值。

June 26, 2020 · 1 min · jiezi