首页
关于
Search
1
给你10个市场数据调研报告的免费下载网站!以后竞品数据就从这里找!
184 阅读
2
php接口优化 使用curl_multi_init批量请求
144 阅读
3
《从菜鸟到大师之路 ElasticSearch 篇》
107 阅读
4
2024年备考系统架构设计师
104 阅读
5
PHP 文件I/O
92 阅读
php
thinkphp
laravel
工具
开源
mysql
数据结构
总结
思维逻辑
令人感动的创富故事
读书笔记
前端
vue
js
css
书籍
开源之旅
架构
消息队列
docker
教程
代码片段
redis
服务器
nginx
linux
科普
java
c
ElasticSearch
测试
php进阶
php基础
登录
Search
标签搜索
php函数
php语法
性能优化
安全
错误和异常处理
问题
vue
Composer
Session
缓存
框架
Swoole
api
并发
异步
正则表达式
php-fpm
mysql 索引
开发规范
协程
dafenqi
累计撰写
786
篇文章
累计收到
33
条评论
首页
栏目
php
thinkphp
laravel
工具
开源
mysql
数据结构
总结
思维逻辑
令人感动的创富故事
读书笔记
前端
vue
js
css
书籍
开源之旅
架构
消息队列
docker
教程
代码片段
副业
redis
服务器
nginx
linux
科普
java
c
ElasticSearch
测试
php进阶
php基础
页面
关于
搜索到
560
篇与
的结果
2023-08-12
把php项目静态编译为二进制发行版
把php项目静态编译为二进制发行版Swoole-Cli 或静态编译PHP 是一个 PHP 的二进制发行版,集成了 swoole、php 内核、php-cli、php-fpm以及多个常用扩展。Swoole-Cli 或静态编译PHP 是全部静态编译打包的,不依赖任何操作系统的so动态链接库,具备非常好的移植性,可以在任意 Linux 系统之间复制,下载即可使用。静态编译无依赖swoole-cli或静态编译PHP 会全部使用静态编译连接方式,libc和libstdc++使用musl,并会包含openssl和curl库和扩展。用户可修改构建脚本添加其他更多三方扩展。使得 Swoole 或PHP程序不再依赖任何系统的so,可在任意Linux系统之间复制分发运行。静态编译是一项比较多见于 Golang 的编译方式,在传统的 Linux 系统下,正常的程序和库基本是动态编译链接(Dynamically linked)的,也就是说,不同程序引用同样的库可以共用,减少资源重复。相关参考{https://zhuanlan.zhihu.com/p/581695339https://zhuanlan.zhihu.com/p/459983471https://www.workerman.net/q/10098https://www.workerman.net/q/10099}项目来源https://github.com/crazywhalecc/static-php-clihttps://github.com/dixyes/phpmicrohttps://github.com/walkor/static-php-clihttps://github.com/crazywhalecc/php-cli-helperPHP静态编译版本下载webman官方提供了一些PHP静态编译版本,就是无需部署PHP环境,就可以独立运行。下载地址 https://www.workerman.net/download各种二进制的资源库https://dl.zhamao.xin/php-bin/file/Swoole-cli下载https://www.swoole.com/download
2023年08月12日
75 阅读
0 评论
0 点赞
2023-08-12
PHP多进程开发[快问快答系列]
PHP多进程开发 快问快答系列 介绍一些简单命令echo $$ //输出当前bash进程strace -s 65500 -p 进程号 //打印进程系统调用kill -s 10 pid //发送信号kill -s SIGUSR2 pid //发送信号pstree -ap //查看进程树ps -ajx //查看进程信息ps 命令字段解析:PPID:父进程IDPID:进程IDPGID:进程组IDSID:会话IDTTY:所在终端STAT:进程状态 R运行 Z僵尸 S睡眠 T停止 D睡眠无法被唤醒UID:unix用户IDCOMMAND:启动命令什么是程序?一般指可执行文件,在 Linux 系统中它按 ELF 格式进行存储,没有后缀可言,file 命令可以查看 elf 文件的具体类型ELF 全程 Executable Linkable Format 可执行可链接格式ELF 分为四大种类EXEC 可执行文件REL 可重定位文件,也称为静态库文件,链接器链接之后成为动态库文件,比如 event.so sockets.so curl.soShared Object File 共享目标文件core dump 存储进程产生的异常信息可通过 objdump/readelf 命令查看 ELF 文件相关信息什么是终端?tty 物理终端tty 是最令人熟悉的了,在 Linux 中,/dev/ttyX 代表的都是上述的物理终端,其中,/dev/tty1~/dev/tty63 代表的是本地终端,也就是接到本机的键盘显示器可以操作的终端/dev/console 当前焦点终端pts 伪终端通过 tcp/ip 协议实现的终端,比如用 SSH 进行的登录,或者 telnet, 那么你将得到一个叫做 /dev/pts/X 的伪终端同时在/proc/bash pid/fd 生成三个标识符指向当前的 /dev/pts/X0 标准输入 鼠标,键盘1 标准输出 显示器2 标准错误 显示器什么是进程?进程退出运行到最后一行语句运行时遇到 return 时运行时遇到 exit () 函数的时候程序异常的时候进程接收到中断信号进程结束时并不会真的退出,还会驻留在内在中,pcntl_wait (pcntl_waitpid) 函数来获取进程的终止状态码同时该函数会释放终止进程的内存空间,如果不这么做,会产生很多僵尸进程占用大量的内存空间孤儿进程父进程运行完,子进程在运行,则子进程会被头号进程 init 接管,这类型的进程成为孤儿进程僵尸进程子进程运行完,父进程没有调用 pcntl_wait () 回收,进程状态变成 Z+守护进程父进程是 init 进程,一般在系统启动时开始运行,除非强行终止,否则直到系统关机都保持运行。守护进程经常以超级用户(root)权限运行,因为它们要使用特殊的端口(1-1024)或访问某些特殊的资源。什么是进程组?多个进程组成一个进程组,每个进程组只有一个组长,组长的 PID 就是进程组的 ID;组内所有进程退出时,进程组才会消失,可以通过 ps -ajx 命令查看 pgid什么是会话?多个进程组组成一个会话,每个会话都有一个会话首进程。会话的特点1) 使用 setsid () 函数可以创建一个新的会话2) 会话首进程无法调用 setsid,会报错3) 非会话首进程进程可调用 setsid 创建出一个新的会话,这个行为会导致该进程会创建一个新的进程组且自身为该进程组组长,该进程会创建出一个新的会话组且自身为该会话组组长,该进程会脱离当前命令行控制终端现实上的比喻就是除了老板之后,员工都可以调用 我上我也行 () 这个函数变成老板且不受原公司的控制什么是信号?信号是进程间通信的其中一种方式,平时用到的 kill -9 pid, 指的不是用第九种方式杀死进程,而是发送信号值为 9 的信号给进程,而刚好信号 9 是 SIGKILL, 功能是停止进程,查看操作系统支持的信号命令: kill -l一般使用 1-31, 注意看没有 32,33 这两个信号信号的产生来源可能是:键盘上按了 Ctrl+C 会产生 SIGINT 信号,关闭终端会产生 SIGHUP 信号硬件也能产生信号使用 kill 命令软件产生,比如在管道里当一侧准备写管道时可能会产生 SIGPIPE 信号当一个进程收到一个信号时,三个可选操作操作系统默认的方式,比如 SIGKILL 就是杀死进程忽略掉这个信号,pcntl_signal (SIGKILL, SIG_IGN, false); 进程收到 SIGKILL 命令时将不为所动有自己的想法,pcntl_signal (SIGKILL, function ($signal){// 自己的想法}, false); 这样将会触发自定义回调pcntl_signal () 信号处理器是会被子进程继承的,所以 fork () 之前最后先行处理信号处理器posix 命令//需要安装posix扩展posix_getpid(); //获取进程IDposix_getppid();//获取父进程IDposix_getpgid(posix_getppid());//获取进程组IDposix_getpgrp());//同上posix_getsid(posix_getpid()));//获取会话IDposix_getuid();//获取当前登录用户UIDposix_getgid();//获取当前登录用户组UIDposix_geteuid();//获取当前有效用户UIDposix_getguid();//获取当前有效用户组UIDposix_kill();//发送信号pcntl 命令//创建一个计时器,在指定的秒数后向进程发送一个SIGALRM信号。每次对 pcntl_alarm()的调用都会取消之前设置的alarm信号。如果seconds设置为0,将不会创建alarm信号。 pcntl_alarm(int $seconds);//在当前进程当前位置产生子进程,子进程会复制父进程的代码段和数据段(Copy on write 写时复制,当子进程要修改内存空间时,操作系统会分配新的内存给子进程),ELF文件的结构,如果父进程先退出,子进程变成孤儿进程,被pid=1进程接管pcntl_fork();//安装一个信号处理器pcntl_signal(int $signo, callback $handler);//调用等待信号的处理器,触发全部未执行的信号回调pcntl_signal_dispatch()//设置或检索阻塞信号pcntl_sigprocmask(int $how, array $set[, array &$oldset])//等待或返回fork的子进程状态,wait函数挂起当前进程的执行直到一个子进程退出或接收到一个信号要求中断当前进程或调用一个信号处理函数。用此函数时已经退出(俗称僵尸进程),此函数立刻返回。子进程使用的所有系统资源将被释放。pcntl_wait($status)//加个WNOHANG参数,不挂起父进程,如果没有子进程退出返回0,如果有子进程退出返回子进程pid,如果返回-1表示父进程已经没有子进程pcntl_wait($status, WNOHANG)//基本同pcntl_wait,waitpid可以指定子进程idpcntl_waitpid ($pid ,$status)pcntl_waitpid ($pid ,$status, WNOHANG)//检查状态代码是否代表一个正常的退出。参数 status 是提供给成功调用 pcntl_waitpid() 时的状态参数。pcntl_wifexited($status)//返回一个中断的子进程的返回代码 当php exit(10)时,这个函数返回10,这个函数仅在函数pcntl_wifexited()返回 TRUE.时有效pcntl_wexitstatus($status)//检查子进程状态码是否代表由于某个信号而中断。参数 status 是提供给成功调用 pcntl_waitpid() 时的状态参数。pcntl_wifsignaled($status)//返回导致子进程中断的信号pcntl_wtermsig($status)//检查子进程当前是否已经停止,此函数只有作用于pcntl_wait使用了WUNTRACED作为 option的时候pcntl_wifstopped($status)//返回导致子进程停止的信号pcntl_wstopsig($status)//检索由最后一个失败的pcntl函数设置的错误数pcntl_errno() pcntl_get_last_error()//检索与给定errno关联的系统错误消息pcntl_strerror(pcntl_errno())pcntl_fork () 执行之前先与 Redis 建立一个连接,然后再开 3 个子进程之后多少个 Redis 连接?<?php$o_redis = new Redis();$o_redis->connect( '127.0.0.1', 6379 );// 使用for循环搞出3个子进程来for ( $i = 1; $i <= 3; $i++ ) { $i_pid = pcntl_fork(); if ( 0 == $i_pid ) {// 使用while保证三个子进程不会退出... while( true ) { sleep( 1 ); }}}// 使用while保证主进程不会退出...while( true ) { sleep( 1 );}netstat -ant |grep 6379说明父进程和三个子进程一共四个进程,实际上共享了一个 Redis 长连接上面这种写法会有什么问题?因为 Redis 是一个单进程单线程的服务器,所以接收到的命令都是顺序执行顺序返回的,所以当客户端多个进程共享一个 redis 连接时,当有四个进程向 Redis 服务端发起请求,返回四个结果,谁先抢到就是谁的,正确的做法是每个子进程创建一个 Redis 连接,或者用连接池孤儿进程怎么产生?$i_pid = pcntl_fork();if (0 == $i_pid) {// 子进程10秒钟后退出. for ($i = 1; $i <= 10; $i++) { sleep(1); echo "我的父进程是:" . posix_getppid() . PHP_EOL; }} else if ($i_pid > 0) {// 父进程休眠2s后退出. sleep(2);}僵尸进程怎么产生?$i_pid = pcntl_fork();if (0 == $i_pid) {// 子进程10s后退出,变成僵尸进程 sleep(10);} else if ($i_pid > 0) {// 父进程休眠1000s后退出. sleep(1000);}子进程怎么回收?$i_pid = pcntl_fork();if (0 == $i_pid) {// 在子进程中 for ($i = 1; $i <= 10; $i++) { sleep(1); echo "子进程PID " . posix_getpid() . "倒计时 : " . $i . PHP_EOL; }} else if ($i_pid > 0) {$i_ret = pcntl_wait($status); echo $i_ret . ' : ' . $status . PHP_EOL; // while保持父进程不退出 while (true) { sleep(1); }}子进程怎么回收?非阻塞版本<?php// fork出十个子进程for ($i = 1; $i <= 10; $i++) {$i_pid = pcntl_fork(); // 每个子进程随机运行1-5秒钟 if (0 == $i_pid) { $i_rand_time = mt_rand(1, 5); sleep($i_rand_time); exit; } // 父进程收集所有子进程PID else if ($i_pid > 0) { }}while (true) {// sleep使父进程不会因while导致CPU爆炸. sleep(1); //设置WNOHANG参数不会阻塞,就是需要外层包个循环 $pid = pcntl_wait($status, WNOHANG); if ($pid == 0) { //目前还没有结束的子进程 continue; } if ($pid == -1) { //已经结束啦 很蓝的啦 exit("所有进程均已终止" . PHP_EOL); } // 如果子进程是正常结束 if (pcntl_wifexited($status)) { // 获取子进程结束时候的 返回错误码 $i_code = pcntl_wexitstatus($status); echo $pid . "正常结束,最终返回:" . $i_code . PHP_EOL; } // 如果子进程是被信号终止 if (pcntl_wifsignaled($status)) { // 获取是哪个信号终止的该进程 $i_signal = pcntl_wtermsig($status); echo $pid . "由信号结束,信号为:" . $i_signal . PHP_EOL; } // 如果子进程是[临时挂起] if (pcntl_wifstopped($status)) { // 获取是哪个信号让他挂起 $i_signal = pcntl_wstopsig($status); echo $pid . "被挂起,挂起信号为:" . $i_signal . PHP_EOL; }}如何创建守护进程?$pid = pcntl_fork();if ($pid > 0) { //1)在父进程中执行fork并exit推出exit();} elseif ($pid == 0) {if (posix_setsid() < 0) { //2)在子进程中调用setsid函数创建新的会话 exit(); } chdir('/'); //3)在子进程中调用chdir函数,让根目录 ” / ” 成为子进程的工作目录 umask(0); //4)在子进程中调用umask函数,设置进程的umask为0 echo "create success, pid = " . posix_getpid(); //5)在子进程中关闭任何不需要的文件描述符 fclose(STDIN); fclose(STDOUT); fclose(STDERR);}//可以把上面封装成函数daemon();while (true) {} //具体业务如何修改进程名?for ($i = 1; $i <= 4; $i++) {$i_pid = pcntl_fork(); if (0 == $i_pid) { //子进程 cli_set_process_title("Worker Process"); //修改子进程的名字 while (true) { sleep(1); } }}cli_set_process_title("Master Process"); //修改父进程的名字while (true) {sleep(1);}进程怎么接收信号?// 信号处理回调function signal_handler($signal){switch ($signal) { case SIGTERM: echo "sigterm信号." . PHP_EOL; break; case SIGUSR2: echo "sigusr2信号." . PHP_EOL; break; case SIGUSR1: echo "sigusr1信号." . PHP_EOL; break; default: echo "其他信号." . PHP_EOL; }}// 给进程安装3个信号处理回调pcntl_signal(SIGTERM, "signal_handler");pcntl_signal(SIGUSR1, "signal_handler");pcntl_signal(SIGUSR2, "signal_handler");while (true) {posix_kill(posix_getpid(), SIGUSR1);//发送一个信号给当前进程 posix_kill(posix_getpid(), SIGUSR1); pcntl_signal_dispatch(); //调一次分发一次信号,调用之前,信号累积在队列里 posix_kill(posix_getpid(), SIGUSR2); posix_kill(posix_getpid(), SIGUSR2); sleep(1); //稍微休息一下}其中第 1,2 行与第 3,4,5,6 行中间隔了一秒,体会一下 pcntl_signal_dispatch 这个函数进程怎么接收信号 (不阻塞版本)?//php7.1及以上才能用这个函数pcntl_async_signals(true);// 信号处理回调function signal_handler($signal){switch ($signal) { case SIGTERM: echo "sigterm信号." . PHP_EOL; break; case SIGUSR2: echo "sigusr2信号." . PHP_EOL; break; case SIGUSR1: echo "sigusr1信号." . PHP_EOL; break; default: echo "其他信号." . PHP_EOL; }}// 给进程安装信号...pcntl_signal(SIGTERM, "signal_handler");pcntl_signal(SIGUSR1, "signal_handler");pcntl_signal(SIGUSR2, "signal_handler");while (true) {posix_kill(posix_getpid(), SIGUSR1);//发送一个信号给当前进程 posix_kill(posix_getpid(), SIGUSR2); sleep(1); //稍微休息一下}进程怎么阻塞信号pcntl_async_signals(true);// 信号处理回调function signal_handler($signal){switch ($signal) { case SIGTERM: echo "sigterm信号." . PHP_EOL; break; case SIGUSR2: echo "sigusr2信号." . PHP_EOL; break; case SIGUSR1: echo "sigusr1信号." . PHP_EOL; break; default: echo "其他信号." . PHP_EOL; }}// 给进程安装信号...pcntl_signal(SIGTERM, "signal_handler");pcntl_signal(SIGUSR1, "signal_handler");pcntl_signal(SIGUSR2, "signal_handler");//把SIGUSR1阻塞,收到这个信号先不处理pcntl_sigprocmask(SIG_BLOCK, [SIGUSR1], $a_oldset);$counter = 0;while (true) {posix_kill(posix_getpid(), SIGUSR1);//发送一个信号给当前进程 posix_kill(posix_getpid(), SIGUSR2); sleep(1); //稍微休息一下 if ($counter++ == 5) { //解除SIGUSR1信号阻塞,并立刻执行SIGUSR1处理回调函数 pcntl_sigprocmask(SIG_UNBLOCK, [SIGUSR1], $a_oldset); }}
2023年08月12日
26 阅读
0 评论
0 点赞
2023-08-12
HTTP[快问快答系列]
[HTTP[快问快答系列]](https://learnku.com/articles/75423)键入网址到网页显示,期间发生了什么?浏览器解析请求的 URLhttp: + // + domain.com + / + index.html协议 + // + 服务器地址 + / + 文件路径生成 HTTP 请求报文GET / HTTP/1.1Accept: /DNS 查询浏览器先查有没这个域名的缓存,如果没有就去问操作系统层面有没这个域名的缓存,如果没有就去操作系统的 hosts 文件查询有没配置.如果没有就去本地 DNS 服务器 (我电脑默认自动获取)如果本地 DNS 服务器也没有域名的缓存就会去问根服务器拿 IP根服务器不负责解析域名,只返回顶级域名的服务器地址,比如.com 域名的服务器地址本地 DNS 服务器去问.com 域名服务器地址拿 IP.com 域名服务器返回负责这个二级域名的 DNS 服务器地址本地 DNS 服务器去问二级域名 DNS 服务器拿 IP成功拿到 IP 并在本地 DNS 服务器,浏览器和操作系统都缓存起来协议栈浏览器通过 DNS 查询到的 IP 和解析 URL 查询到的端口用操作系统提供的 socket 库连接服务器,通过三次握手建立 tcp 连接,客户端和服务器双方生成通信 socket 文件$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);socket_connect($socket, 'ip', '端口');TCP 层 可靠传输建立好 tcp 连接之后,HTTP 报文加上 TCP 报文头部,如果报文长度超过了 MSS 长度就会拆解分包发送IP 层 远程定位TCP 报文头部加上 IP 报文头部MAC 层 两点传输IP 报文头部加上 MAC 报文头部网卡把报文转换成电信号,发送到交换机,再发送到路由器,路由器转发上层路由器一直到达服务器服务器按同样的步骤组装返回报文,原路返回逐层去掉头部最终返回到浏览器的 http 报文长这个样子HTTP/1.1 200 OKDate: Mon, 23 May 2005 22:38:34 GMTContent-Type: text/html; charset=UTF-8Content-Length: 155Connection: close An Example PageHello World, this is a very simple HTML document.GET 与 POST 的区别GET浏览器对 GET 请求的 URL 会有长度限制,对 GET 请求可以缓存,也可以保存书签,历史记录,只支持 url 编码POSTPOST 请求的数据在浏览器 URL 上不可见,支持 url 编码,multipart/form-data 等编码,总结以上是 GET 和 POST 在浏览器上的区别,在 HTTP 协议上,并没有本质的区别,一般 GET 用来获取数据,POST 用来提交数据,GET 也可以像 POST 一样传 body, 只不过 RFC 规范不建议你这么做HTTP 缓存有哪些实现方式?强制缓存Cache-Control 是 HTTP/1.1 的标准,而 Expires 则是 HTTP/1.0 的标准,Cache-Control 的优先级高于 Expires。通常使用 Cache-Control, 比较灵活。Cache-Control:public:响应可以被客户端和代理服务器缓存。private:响应只能被客户端缓存,不能被代理服务器缓存。no-cache:客户端和代理服务器都不能缓存响应,需要重新获取。no-store:响应不能被缓存或存储。max-age:响应的最大有效时间,单位为秒。s-maxage:覆盖 max-age,仅适用于共享缓存,例如代理服务器。Expires:过期时间:响应的绝对过期时间,使用 GMT 格式表示。协商缓存协商缓存需要配合强制缓存中 Cache-Control 来使用,只有在未能命中强制缓存的时候,才能发起带有协商缓存字段的请求。服务器根据一下两种方式判断文件没有修改则返回 304 Not Modified,不会返回资源 1.请求头If-Modified-Since和响应头Last-Modified 2.请求头If-None-Match与响应头部ETag HTTP 常见的状态码有哪些?1xx 类状态码属于提示信息,是协议处理中的一种中间状态,实际用到的比较少。200 : 表示一切正常。204 : 与 200 OK 基本相同,但响应头没有 body 数据206 : 应用于 HTTP 分块下载或断点续传301 : 永久重定向302 : 临时重定向,说明请求的资源还在304 : 表示资源未修改,重定向已存在的缓冲文件400 : 客户端请求的报文有错误403 : 服务器禁止访问这个资源404 : 资源在服务器上不存在500 : 服务器发生了错误501 : 客户端请求的功能服务端还没法开发好502 : phpfpm 发生错误时,nginx 返回的状态码503 : 服务器当前很忙,暂时无法响应客户端HTTP/1.1 相比 HTTP/1.0 提高了什么性能?使用长连接的方式改善了 HTTP/1.0 短连接造成的性能开销。HTTP/2 做了什么优化?HTTP/2 协议是基于 HTTPS 的,所以 HTTP/2 的安全性也是有保障的。头部压缩HTTP/2 会压缩头(Header)如果你同时发出多个请求,他们的头是一样的或是相似的,那么,协议会帮你消除重复的部分。这就是所谓的 HPACK 算法:在客户端和服务器同时维护一张头信息表,所有字段都会存入这个表,生成一个索引号,以后就不发送同样字段了,只发送索引号,这样就提高速度了。二进制格式全面采用了二进制格式,头信息和数据体都是二进制,并且统称为帧,收到报文后,无需再将明文的报文转成二进制,而是直接解析二进制报文,这增加了数据传输的效率并发传输引出了 Stream 概念,多个 Stream 复用在一条 TCP 连接。服务器推送主动向客户端发送消息。HTTP/2 有什么缺陷?HTTP/2 通过 Stream 的并发能力,解决了 HTTP/1 队头阻塞的问题,看似很完美了,但是 HTTP/2 还是存在 “队头阻塞” 的问题,只不过问题不是在 HTTP 这一层面,而是在 TCP 这一层。HTTP/2 是基于 TCP 协议来传输数据的,TCP 是字节流协议,TCP 层必须保证收到的字节数据是完整且连续的,这样内核才会将缓冲区里的数据返回给 HTTP 应用,那么当「前 1 个字节数据」没有到达时,后收到的字节数据只能存放在内核缓冲区里,只有等到这 1 个字节数据到达时,HTTP/2 应用层才能从内核中拿到数据,这就是 HTTP/2 队头阻塞问题。所以,一旦发生了丢包现象,就会触发 TCP 的重传机制,这样在一个 TCP 连接中的所有的 HTTP 请求都必须等待这个丢了的包被重传回来。HTTP/3 做了哪些优化?无队头阻塞使用 QUIC 协议 底层是 UDP连接迁移 对移动设备非常友好HTTPS 是如何建立连接的?其间交互了什么?首先三次握手建立 TCP 连接,成功之后马上建立 SSL/TCS 连接SSL/TLS 协议基本流程:客户端向服务器索要并验证服务器的公钥。双方协商生产「会话秘钥」。双方采用「会话秘钥」进行加密通信。SSL/TLS 协议详细流程:ClientHello首先,由客户端向服务器发起 ClientHello 请求。在这一步,客户端主要向服务器发送以下信息:(1)客户端支持的 TLS 协议版本,如 TLS 1.2 版本。(2)客户端生产的随机数(Client Random),后面用于生成「会话秘钥」条件之一。(3)客户端支持的密码套件列表,如 RSA 加密算法。SeverHello服务器收到客户端请求后,向客户端发出响应,也就是 SeverHello。服务器回应的内容有如下内容:(1)确认 TLS 协议版本,如果浏览器不支持,则关闭加密通信。(2)服务器生产的随机数(Server Random),也是后面用于生产「会话秘钥」条件之一。(3)确认的密码套件列表,如 RSA 加密算法。(4)服务器的数字证书。客户端回应客户端收到服务器的回应之后,首先通过浏览器或者操作系统中的 CA 公钥,确认服务器的数字证书的真实性。如果证书没有问题,客户端会从数字证书中取出服务器的公钥,然后使用它加密报文,向服务器发送如下信息:(1)一个随机数(pre-master key)。该随机数会被服务器公钥加密。(2)加密通信算法改变通知,表示随后的信息都将用「会话秘钥」加密通信。(3)客户端握手结束通知,表示客户端的握手阶段已经结束。服务器和客户端有了这三个随机数(Client Random、Server Random、pre-master key),接着就用双方协商的加密算法,各自生成本次通信的「会话秘钥」。服务器的最后回应服务器收到客户端的第三个随机数(pre-master key)之后,通过协商的加密算法,计算出本次通信的「会话秘钥」。然后,向客户端发送最后的信息:(1)加密通信算法改变通知,表示随后的信息都将用「会话秘钥」加密通信。(2)服务器握手结束通知,表示服务器的握手阶段已经结束。至此,整个 TLS 的握手阶段全部结束。接下来,客户端与服务器进入加密通信,就完全是使用普通的 HTTP 协议,只不过用「会话秘钥」进行对称加密内容。CA 证书签发过程首先 CA 会把持有者的公钥、用途、颁发者、有效时间等信息打成一个包,然后对这些信息进行 Hash 计算,得到一个 Hash 值;然后 CA 会使用自己的私钥将该 Hash 值加密,生成 Certificate Signature,也就是 CA 对证书做了签名;最后将 Certificate Signature 添加在文件证书上,形成数字证书;吐槽一下动动手的事情竟然要卖几千块一年客户端校验 CA 证书的流程是怎样的?首先客户端会使用同样的 Hash 算法获取该证书的 Hash 值 H1;通常浏览器和操作系统中集成了 CA 的公钥信息,浏览器收到证书后可以使用 CA 的公钥解密 Certificate Signature 内容,得到一个 Hash 值 H2 ;最后比较 H1 和 H2,如果值相同,则为可信赖的证书,否则则认为证书不可信。HTTPS 一定安全可靠吗?不一定,如果客户端通过浏览器向服务端发起 HTTPS 请求时,被「假基站」转发到了一个中间人服务器,形成中间商赚差价,简称中间人攻击客户端向中间人服务器发起 https 请求中间人服务器返回自己的 CA 证书成功建立连接中间人成功解密获取客户端发送的加密报文中间人服务器再跟目标服务器建立 https 连接转发客户端的数据给目标服务器转发目标服务器的报文给客户端这种攻击的前提是你信任了中间人服务器的 CA 证书,或者被木马植入了中间人的 CA 证书,https 协议本身是没漏洞的,中间人攻击本质是利用了客户端的漏洞,不关 https 的事情为什么抓包工具能截取 HTTPS 数据?工作原理跟中间人攻击一致如何避免被中间人抓取数据?通过 HTTPS 双向认证来避免这种问题。这样客户端也要有自己的 CA 证书,双方交换证书确认身份再建立连接
2023年08月12日
11 阅读
0 评论
0 点赞
2023-08-12
Composer命令全解析
Composer中文文档Composer命令全解析常用命令镜像配置中国镜像composer config -g repo.packagist composer https://packagist.phpcomposer.com配置其他厂商镜像阿里云 (好像说停用了)composer config -g repo.packagist composer https://mirrors.aliyun.com/composer/腾讯composer config -g repo.packagist composer https://mirrors.cloud.tencent.com/composer/华为composer config -g repo.packagist composer https://repo.huaweicloud.com/repository/php/解除镜像composer config -g --unset repos.packagist项目搜索项目composer search ThinkPHP创建项目composer create-project topthink/ThinkPHP=5.1.* ./tp5安装扩展composer require laravel/laravel ">=5.5"移除扩展composer remove laravel/laravel生产最佳实践转换 PSR-0/4 autoloading 到 classmap 获得更快的载入速度,禁用开发者模式composer dump-autoload -o --no-dev 自动加载 autoload目前支持四种自动加载方式:PSR-0PSR-0 规范是 PHP5.2 之前的一种命名空间映射规范,它规定命名空间与文件路径的对应关系如下命名空间中的每个下划线字符(_)都会被转换成目录分隔符(/);命名空间中的每个命名空间分隔符(\)都会被转换成目录分隔符(/);命名空间中的首字母和下划线字符都会被转换成目录名和文件名中的小写字母;每个类的文件名必须与类名完全一致,包括大小写。"psr-0" : { "Foo\\" : "psr0src/", # "Foo_Bar_" : "psr0src/" },composer install/update 之后,PSR-0 引用全部合并到 vendor/composer/autoload_namespaces.phpPSR-4PSR-4 规范是较新的一种命名空间映射规范,它与 PSR-0 规范的区别在于:命名空间中的下划线字符不再被特殊处理,只有命名空间分隔符(\)会被转换成目录分隔符(/);命名空间中的首字母和下划线字符不再被强制转换成小写字母;类的文件名与类名可以不完全一致,但必须满足相对文件路径和类名的对应关系"psr-4": { #查找Afishpapa\Httptool\Http类时的路径为src/Http.php "Afishpapa\\Httptool\\": "src/" #可以在src/和lib/ 下面找 Monolog命名空间下的类 "psr-4": { "Monolog\\": ["src/", "lib/"] } #所有命名空间都来src/目录下找 "" : "src/" }composer install/update 之后,PSR-4 引用全部合并到 vendor/composer/automoad_psr4.php 中。return array( 'Afishpapa\\Httptool\\' => array($baseDir . '/src'), );Classmapcomposer install/update 之后,PSR-4 引用全部合并到 vendor/composer/autoload_classmap.php 中。你可以用 classmap 生成支持支持自定义加载的不遵循 PSR-0/4 规范的类库。Files通常作为函数库的载入方式(而非类库)。{ "autoload": { "files": ["src/MyLibrary/functions.php"] } }全局配置-v : 增加消息的详细程度,正常输出-vv : 增加消息的详细程度,更加详细得输出-vvv : 增加消息的详细程度,debug用-h : 显示帮助-q : 不要显示任何信息-n : 不要问任何交互问题-d : 设置工作目录--ansi: 强制输出 ANSI 编码--no-ansi: 禁用 ANSI 编码--version (-V): 展示所有应用版本--profile: 展示时间和内存信息常用配置--prefer-install: 默认值为distdist: 检查本地缓存压缩包,如果有直接复制到vendor目录,如果本地缓存没有,则去远程仓库下载压缩包,如果远程仓库没有提供压缩包,则尝试从github中安装包,并且删除.git版本信息,总之,dist能够快速地下载并安装依赖包,适用于大部分生产环境。 source: 直接从github中下载源码,保留.git信息,如果您需要对包进行自定义修改或者需要对其进行特殊的构建过程,则应该使用 source。 auto:2.1版本后已弃用-o: 生成自动加载器文件的优化版本,以加快类加载速度。-a: 默认情况下,Composer 会根据 composer.json 中的 PSR-4 和 PSR-0 配置来生成自动加载器, 使用 --classmap-authoritative 选项可以让 Composer 忽略 PSR-4 和 PSR-0 配置,而直接根据类文件生成一个类映射表(class map),并将其作为自动加载器的唯一来源。需要注意的是,使用 --classmap-authoritative 选项可能会导致一些问题,比如在添加新的类文件时需要重新生成类映射表,否则新添加的类无法被自动加载器加载。因此,建议在开发环境中使用这个选项来提高性能,但在生产环境中不要使用,以免出现问题。--dry-run: 执行安装过程的模拟运行,不会实际下载或安装任何软件包。--dev: 安装开发依赖项,包括测试框架和调试工具等。composer init以交互方式初始化 composer--name: 包名,格式为作者/名称,比如monolog/monolog--description: 简短描述--author: 作者名--type: 包的安装类型,默认librarylibrary : 它会简单的将文件复制到 vendor 目录 project : 当前包是一个项目,而不是一个库 metapackage : 一个空的包,包含依赖并且需要触发依赖的安装,这将不会对系统写入额外的文件。 composer-plugin : 它有一个自定义安装类型,可以为其它包提供一个 installler。--homepage: 官网首页--require: 引入包,格式为 包:版本 foo/bar:1.0.0--require-dev: 开发用的组件-s : 最小稳定性值 dev stable --license (-l): 许可证--repository: 指定一个或多个 Composer 仓库-a : 添加一个autoload.psr-4的对象到composer.jsoncomposer install如果存在 composer.lock 文件,它会从此文件读取依赖版本,这确保了该库的每个使用者都能得到相同的依赖版本。如果不存在 composer.lock 文件,它会从 composer.json 文件读取依赖版本,并把其安装到 vendor 目录下。如果没有 composer.lock 文件,composer 将在处理完依赖关系后创建它。composer require添加一个包到 composer.json 文件,如果没有 composer.json 就创建一个# 该命令会安装两个不同的软件包 # vendor/package:2.* : 版本号以 2. 开头,后面跟着任何版本号。 # vendor/package2:dev-master : 使用 dev-master 分支。这意味着它将安装该分支的最新版本,通常是开发版本,不属于正式发布。 composer require "vendor/package:2.*" vendor/package2:dev-mastercomposer update获取依赖的最新版本# 只更新这两个包vendor/package vendor/package2 composer update vendor/package vendor/package2 # 更新符合正则匹配的包 composer update "vendor/*" # 更新依赖包到指定版本,需符合composer.json的约束 composer update --with vendor/package:2.0.1composer remove移除依赖包# 移除这两个包 composer remove vendor/package vendor/package2 composer reinstall 重装包,如果不小心改了包文件,可以使用重装命令恢复 # 重装两个包 composer reinstall acme/foo acme/bar # 重装正则匹配的包 composer.phar reinstall "acme/*"composer check-platform-reqs用于检查您的 PHP 和扩展版本是否符合已安装包的平台要求--lock: 仅从锁定文件中检查要求,而不是从已安装的包中检查要求。 --no-dev: 不检查 require-dev 包要求。 -f: 格式> composer check-platform-reqs Checking platform requirements for packages in the vendor dir ext-json 1.7.0 success ext-libxml 7.3.4 success ext-mbstring 7.3.4 success ext-openssl 7.3.4 success ext-simplexml 7.3.4 success php 7.3.4 successcomposer globalglobal 允许您全局运行其他命令,如 install、remove、require,updatecomposer search monolog搜索依赖包-N : 只搜包名-O : 只搜作者-t : 搜全称λ composer search monolog monolog/monolog Sends your logs to files, sockets, inboxes, databases and various web services symfony/monolog-bundle Symfony MonologBundle symfony/monolog-bridge Provides integration for Monolog with various Symfony components ...composer show / composer info列出所有可用的包信息λ composer show defuse/php-encryption v2.3.1 Secure PHP Encryption Library laminas/laminas-diactoros 2.5.0 PSR HTTP Message implementations laminas/laminas-zendframework-bridge 1.4.1 Alias legacy ZF class names to Laminas Project equivalents. ...列出单个包的详情λ composer show slim/slim name : slim/slim descrip. : Slim is a PHP micro framework that helps you quickly write simple yet powerful web applications and APIs keywords : api, framework, micro, router versions : * 3.12.4 type : library license : MIT License (MIT) (OSI approved) https://spdx.org/licenses/MIT.html#licenseText homepage : https://slimframework.com source : [git] https://github.com/slimphp/Slim.git ce3cb65a06325fc9fe3d0223f2ae23113a767304 dist : [zip] https://api.github.com/repos/slimphp/Slim/zipball/ce3cb65a06325fc9fe3d0223f2ae23113a767304 ce3cb65a06325fc9fe3d0223f2ae23113a767304 path : D:\workspace\oauth\examples\vendor\slim\slim names : slim/slim, psr/http-message-implementation support issues : https://github.com/slimphp/Slim/issues source : https://github.com/slimphp/Slim/tree/3.12.4 autoload psr-4 Slim\ => Slim requires ext-json * ext-libxml * ext-simplexml * nikic/fast-route ^1.0 php >=5.5.0 pimple/pimple ^3.0 psr/container ^1.0 psr/http-message ^1.0 requires (dev) phpunit/phpunit ^4.0 squizlabs/php_codesniffer ^3.6.0 provides psr/http-message-implementation 1.0composer outdated列出所有安装包是否可以更新λ composer outdated Direct dependencies required in composer.json: laminas/laminas-diactoros 2.5.0 2.14.0 PSR HTTP Message implementations league/event 2.2.0 3.0.1 Event package slim/slim 3.12.4 4.9.0 Slim is a PHP micro framework that helps you quickly write simple yet po... Transitive dependencies not required in composer.json: psr/container 1.1.1 2.0.1 Common Container Interface (PHP FIG PSR-11)composer browse / composer home浏览器直接打开这个包的 github 仓库# 打开这个包的官网 composer browser -H slim/slim # 打印slim的github仓库链接 composer browser -s slim/slimcomposer suggests给你人生路上一点建议λ composer suggests lcobucci/jwt suggests: - lcobucci/clock: * 1 additional suggestions by transitive dependencies can be shown with --all composer fund给出你所用的包的捐赠链接composer depends / whycomposer depends 命令用于显示一个包的依赖关系树。如果你要删除一个包之前,可以用这个命令先看看它上面是不是有人> composer depends psr/log -t psr/log 1.1.4 Common interface for logging libraries ├──composer/composer 2.4.x-dev (requires psr/log ^1.0 || ^2.0 || ^3.0) ├──composer/composer dev-main (requires psr/log ^1.0 || ^2.0 || ^3.0) ├──composer/xdebug-handler 3.0.3 (requires psr/log ^1 || ^2 || ^3) │ ├──composer/composer 2.4.x-dev (requires composer/xdebug-handler ^2.0.2 || ^3.0.3) │ └──composer/composer dev-main (requires composer/xdebug-handler ^2.0.2 || ^3.0.3) └──symfony/console v5.4.11 (conflicts psr/log >=3) (circular dependency aborted here)composer prohibits / why-not告诉您哪些包在阻止你想安装的包,并给出理由composer validate如果你手动修改 composer.json, 当准备提交 composer.json 文件之前,最好执行这条命令检查一下composer status如果你手动修改过一个包,这个包安装来源是 source, 则可以用这个命令看你本地修改记录,相当于 git statuscomposer self-update / selfupdatecomposer 程序自更新# 更新到指定版本 composer self-update 2.4.0-RC1composer config修改当前项目或者全局的配置-g : 修改全局配置文件--unset: 移除配置-l: 展示全部配置信息,如果加上-g,就显示全局的--absolute: *-dir的配置返回绝对路径--append: 追加一个镜像时,设置比较低的优先级--source: 展示config从哪里加载的# 添加一个测试foo到repositories composer config repo.foo vcs https://github.com/foo/bar # 添加一个阿里云镜像到repositories(阿里云镜像凉了) composer config repo.packagist composer https://mirrors.aliyun.com/composer/ #效果如下 "repositories": { "packagist": { "type": "composer", "url": "https://mirrors.aliyun.com/composer/" }, "foo": { "type": "vcs", "url": "https://github.com/foo/bar" } } # 修改extra配置 composer config extra.foo.bar value composer config --json extra.foo.bar '{"baz": true, "qux": []}'composer create-project创建项目 / 包,相当于 git clone + composer installcomposer create-project doctrine/orm path "2.2.*"composer dump-autoload当修改了包里面的类名,或者增加删除文件之后,需要执行这个命令# -o 选项是为了生产环境中的性能优化, composer dump-autoload -o # -a 选项则是为了开发环境中的重新生成类映射。 composer dump-autoload -acomposer clear-cache / clearcache / cc清理本地包缓存archive从远程下载一个包,并打包成 zip/tar 压缩包php composer.phar archive vendor/package 2.0.21 --format=ziprun-script / run你可以运行此命令来手动执行,只需要指定脚本的名称,可选的 --no-dev 参数允许你禁用开发者模式。{ "scripts": { "post-update-cmd": "MyVendor\\MyClass::postUpdate", "post-package-install": [ "MyVendor\\MyClass::postPackageInstall" ], "post-install-cmd": [ "MyVendor\\MyClass::warmCache", "phpunit -c app/" ] } } # 将会运行所有 post-install-cmd 事件下定义的脚本。 `composer run-script post-install-cmd` diagnose可以用来检查当前 Composer 环境是否符合最佳实践,包括 PHP 环境、Composer 配置等。audit检查当前项目的依赖项是否存在已知的安全漏洞。help使用 help 可以获取指定命令的帮助信息。php composer.phar help install
2023年08月12日
20 阅读
0 评论
0 点赞
2023-08-12
Hyperf 3.0
Hyperf 3.0回顾在过去的一年半时间里,Hyperf 2.2 共发布了 35 个小版本,使 Hyperf 达到了一个前所未有的高度,这里也获得了一些不错的数据反馈。Hyperf 在 GitHub 和 Gitee 上的关注度也得到了显著提升,分别获得了 4.9k 和 791 个 star,整体关注度增长也很稳定。Hyperf 框架的安装量也达到了 90万次,每天都有约 1300次的安装,这也表明了 Hyperf 已经广泛应用于相关行业中并支撑了大量的系统运行。Hyperf 组织下的有效 repo 更是达到了约 140个(去除掉 Archive 项目后),维护工作量空前巨大,但迭代仍然高频。感谢 Hyperf 团队全体成员的辛勤以及贡献,同时也感谢所有的 PR 贡献者,没有你们的参与也就没有今天的 Hyperf。Thanks ALL ContributorsHyperf 3.0 新时代Hyperf 3.0 带来了很多非常有意思的新能力,其中一些新能力不乏是 PHP 领域里面前所未有的,当然这些新能力也脱离不了其他开源社区的积极发展,包括但不限于 PHP、Swoole、Swow、PHPMicro、DTM、Seata 等开源社区,也衷心希望大家在闲暇时间可以为这些开源社区也贡献出自己的一份力,搭上一砖一瓦,共建更加美好的未来。原生注解 (Attribute)随着 PHP 8.1、8.2 的发布,给 PHP 带来了很多新的特性,其中与 Hyperf 最为相关的就是 PHP 的原生注解(Attribute) 了,Hyperf 3.0 也放弃了过往采用的基于注释解析的注解功能实现,转而采用 PHP 的原生注解,当然对应依赖的 PHP 版本,也将调整为最低要求 PHP 8.0。我们以一个最简单的 Controller 案例来呈现新的原生注解的使用:<?phpdeclare(strict_types=1);namespace App\Controller;use Hyperf\HttpServer\Contract\RequestInterface;use Hyperf\HttpServer\Annotation\Controller;use Hyperf\HttpServer\Annotation\RequestMapping;[Controller]class IndexController{// Hyperf 会自动为此方法生成一个 /index/index 的路由,允许通过 GET 或 POST 方式请求 #[RequestMapping(path: "index", methods: "get,post")] public function index(RequestInterface $request) { // 从请求中获得 id 参数 $id = $request->input('id', 1); return (string)$id; }}同时随着原生注解的应用,在 3.0 中也能够支持在同一个位置重复应用同一个注解了,比如过往在一个 Controller Action 想要应用多个 Middleware 时,需要通过 @Middlewares 注解包含多个 @Middleware 注解实现应用,而在 3.0 则可直接书写多个 @Middleware 注解实现该应用。同时在 3.0 中,注解也可以应用在方法的参数上,以实现一些针对方法参数定义、参数解析等功能。从 注释注解 调整为 原生注解,也无需担忧过往项目的迁移改造工作量,Hyperf 也提供了对应的工具一键自动转换,只需要在 2.2 时引入 hyperf/code-generator 组件,并执行 php bin/hyperf.php code:generate -D app 命令,即可将 app 文件夹内的注释注解自动转为原生注解,轻松省力~分布式事务在过去的一年里,Hyperf 团队也为 PHP 领域孵化了两个前所未有的分布式事务组件并贡献到对应的开源社区,对应 DTM (首个基于 Go 语言实现的流行分布式事务管理器) 与 Seata (由阿里巴巴开源的流行分布式事务管理器) 两款主流的开源分布式事务管理器,分别是 dtm-php/dtm-client 和 seata/seata-php ,其中 dtm-php 是实现了 dtm 完整功能的分布式事务客户端,已支持 TCC模式、Saga、XA、二阶段消息模式的分布式事务模式,并分别实现了与 DTM Server 以 HTTP 协议 或 gRPC 协议 通讯,该客户端可安全运行于 PHP-FPM 和 Swoole 协程环境中,更是对 Hyperf 框架做了更加易用的功能支持,可应用于生产环境中,而 seata-php 仍在开发迭代中,尚未能用于生产环境,也希望能有更多人参与进来共同迭代。我们也以一个简单的例子来说明如何在 Hyperf 中实现一个 TCC 分布式事务的调用,其它分布式事务模式可查阅 dtm-php repo 的 README 文件,或 Hyperf 3.0 文档关于分布式事务一章。<?phpnamespace App\Controller;use DtmClient\TCC;use DtmClient\TransContext;use Hyperf\Di\Annotation\Inject;use Hyperf\HttpServer\Annotation\Controller;use Hyperf\HttpServer\Annotation\GetMapping;use Throwable;[Controller(prefix: '/tcc')]class TccController{protected string $serviceUri = 'http://127.0.0.1:9501'; #[Inject] protected TCC $tcc; #[GetMapping(path: 'successCase')] public function successCase() { try { $this->tcc->globalTransaction(function (TCC $tcc) { // 创建子事务 A 的调用数据 $tcc->callBranch( // 调用 Try 方法的参数 ['amount' => 30], // Try 方法的 URL $this->serviceUri . '/tcc/transA/try', // Confirm 方法的 URL $this->serviceUri . '/tcc/transA/confirm', // Cancel 方法的 URL $this->serviceUri . '/tcc/transA/cancel' ); // 创建子事务 B 的调用数据,以此类推 $tcc->callBranch( ['amount' => 30], $this->serviceUri . '/tcc/transB/try', $this->serviceUri . '/tcc/transB/confirm', $this->serviceUri . '/tcc/transB/cancel' ); }); } catch (Throwable $e) { var_dump($e->getMessage(), $e->getTraceAsString()); } // 通过 TransContext::getGid() 获得 全局事务ID 并返回 return TransContext::getGid(); } }至于其它事务模式,如 Saga、XA、二阶段消息模式等,可以具体查阅 dtm-php/dtm-client 仓库的 Readme 文件或 Hyperf 3.0 的相关文档。Swow 网络引擎实际上在 Hyperf 2.2 中,就已经支持了 Swow 网络引擎的运行,随着 Swow 1.0 正式版的发布,在 Hyperf 3.0 中,我们也把 Swow 的应用提高到了一个更高的高度,Swow 实现了一套有史以来最完整的 PHP 协程模型,它全面释放了 PHP 的真正实力,使得开发者可以做到以往难以想象的事情,对比 Swoole 它具备更好的兼容性、可调试性、可编程性,它甚至能使 Hyperf 运行于原生 Windows 环境下而无需借助 WSL 或 Docker,同时也提供了 SDB 和 Watchdog 工具对协程运行进行调试和监控,极大的提升了 Hyperf 的可调试性。我们提供了一个全新的 Skeleton 骨架项目用于快速创建一个基于 Swow 网络引擎的 Hyperf 应用,以下是一个简单的通过 Composer 创建应用的流程:composer create-project hyperf/swow-skeleton:dev-master 创建后,确保您的 PHP 环境已经安装好了 Swow 扩展,便可直接通过 php bin/hyperf.php start 命令启动服务,整体使用与原来无异,Hyperf 底层已做好了适配。在 Windows 环境中也只需在 CMD 或者 Poweshell 中运行即可哦~SDB 协程调试器SDB 是一款使用 PHP 语言编写的协程调试器工具,使用上类似于 GDB,它具有以下的几个优点:使用简单,只需要一行代码即可开启;无需端口,可直接运行在 TTY 上;零成本,可在生产环境使用,不影响性能;功能强大,深度定制,量身打造类微型操作系统;通过 SDB,您可以对运行中的 Hyperf 应用进行交互,以实现查看当前所有协程状态、窥视协程、进入指定协程、查看调用栈、打断点、单步调试、查看及修改变量调试、扫描僵尸协程、Kill 协程等操作,真正意义上的将 PHP 协程带到了工程化的实用阶段。WatchdogWatchdog 为 PHP 提供了 CPU 调度能力,其核心原理是 Watchdog 线程会定期检查其它线程中协程的活跃度情况,若发现工作线程中的协程不再活跃,则通过 ZendVM 的中断机制对其进行状态确认,若 VM 中断失败,则表明工作线程陷入了系统调用阻塞,触发告警;若 VM 中断成功,则表明工作线程陷入了 CPU 密集运算或死循环,则立即触发用户设定的调度规则进行调度。通过 Watchdog 可以实现 可编程的协程调度机制,可以非常方便的解决过往头疼的 CPU 饥饿 问题,以下是一些用法的演示:// 运行超过 1ms 就让出控制权\Swow\WatchDog::run(1 1000 1000);// 运行超过 1ms 就让出 10ms,调度失败并超过 5ms 时视为系统调用阻塞\Swow\WatchDog::run(1 1000 1000, 5 1000 1000, 10);// 可编程方式,函数会在程序阻塞 100ms 后触发$alertCountMap = new WeakMap();\Swow\WatchDog::run(quantum: 100 1000 1000, alerter: static function () use ($alertCountMap): void {$coroutine = Coroutine::getCurrent(); $alertCount = ($alertCountMap[$coroutine] ??= 0) + 1; $alertCountMap[$coroutine] = $alertCount; echo 'CPU starvation occurred, suspend this coroutine...' . PHP_EOL; sleep(0); if ($alertCount > 5) { echo 'Kill the bad guy' . PHP_EOL; $coroutine->kill(); }});更多用法关于 SDB 和 WatchDog 以及更多用法目前文档可能尚未完善,我们接下来也会编写多篇文章来阐述用法,也会尽快完善相关文档~BoxBox 是一个致力于帮助提升 PHP 应用程序的编程体验的工具,尤其有助于 Hyperf 应用,可以用于管理 PHP 环境和相关依赖,同时提供将 PHP 应用程序打包为二进制程序的能力,还提供反向代理服务来管理和部署 Swoole/Swow 服务。这些能力也是前所未有的,特别是将 Hyperf 或 PHP 应用打包为二进制程序的能力,打包好的程序,可以不依赖系统的 PHP 环境单独运行,以达到类似于 Go 语言的打包能力,这些能力也得益于 phpmicro 的发展,而 Box 则是站在巨人的肩膀上,将这些能力以更加简单易用的方式提供给大家使用~以下是一个通过下载 Box 到创建一个 Hyperf 应用,并运行的简单案例:安装 Box// Macwget https://github.com/hyperf/box/releases/download/v0.5.5/box_x86_64_macos -O boxsudo mv ./box /usr/local/bin/boxsudo chmod 755 /usr/local/bin/box// 确保 /usr/local/bin/box 在你的 $PATH 环境中,或者将 box 放到你想要的任意 $PATH 路径中// Linux x86_64wget https://github.com/hyperf/box/releases/download/v0.5.5/box_x86_64_linux -O boxsudo mv ./box /usr/local/bin/boxsudo chmod 755 /usr/local/bin/box// 确保 /usr/local/bin/box 在你的 $PATH 环境中,或者将 box 放到你想要的任意 $PATH 路径中// Windowscurl -o box.exe https://github.com/hyperf/box/releases/download/v0.5.5/box_x64_windows.exe// 将 box.exe 放到你想要的任意 Path 环境变量路径中,同时 Windows 版本在执行时需要在命令行中使用 box.exe 而不是 box初始化 Github Access TokenBox 需要一个 Github 访问令牌来请求 Github API,以便于从 GitHub Actions 的 Artifacts 中检索包的版本。创建 Github Access Token,workflow 范围需要勾选;运行 box config set github.access-token 命令来设置您的 token;我们将在 v0.6 版本让使用 Box 前无需设置 Github Access Token,以提供更加简便的使用体验,请期待~通过 Box 初始化 PHP 环境并启动 Hyperf// 通过 box 安装 PHP 8.1,此安装不会影响系统原来自身安装的 PHPbox get php@8.1// 通过 box 安装 composerbox get composer// 通过 box composer 创建 hyperf 应用,可指定 dev-master 分支以防止 packagist 代理数据落后的问题box composer create-project hyperf/swow-skeleton:dev-master// 通过 box 启动 hyperfbox hyperf start至此一个完整的安装和运行流程已完成,我们可以发现过往复杂的环境部署环节,已经简化为了区区几个命令,通过 && 连接符甚至可以组成一行命令足以。通过 Box 打包 Hyperf 应用为二进制程序这个神奇的能力,在操作上也被简化得匪夷所思,只需预先执行 box build-prepare 命令提前下载好相关依赖,这个命令只需执行一次即可,后续即可通过 box build 命令对当前所在文件夹的 Hyperf 应用进行打包动作。打包好后,当前文件夹会出现一个名为 hyperf 的二进制文件,后续只需要通过 hyperf start 命令即可启动该 Hyperf 应用。Box 自身就是一个基于 Box 打包出来的 Hyperf 应用,大家也可以通过了解 Box 项目本身,来了解该能力的使用。Box Kernel 切换默认情况下,Box 由 Swow Kernel 提供支持,但是我们也提供了 Swoole Kernel,您可以通过 box config set kernel swoole 来切换为 Swoole Kernel,但是需要注意的是,Swoole Kernel 仅支持 PHP 8.1 版本,且不支持构建二进制程序功能和 Windows 系统环境。// 设置为 Swow Kernel [默认]box config set kernel swow// 设置为 Swoole Kernel (不支持 Windows)box config set kernel swooleBox 的更多能力Box 还有更多有意思的使用方法和工具组合,可以通过下面的部分的命令清单快速一览命令box get pkg@version从远程安装包,pkg是包名,version是包的版本,box get pkg表示安装最新版本的 pkg,例如, 运行 box get php@8.1 安装 PHP 8.1, 运行 box get composer 安装最新的 composer binbox build-prepare 为 build 和 build-self 命令做好相关环境的准备box build-self 构建 box bin 本身box build 将 Hyperf 应用程序构建成二进制文件box self-update 将 box bin 更新至最新版本box config set-php-version 设置 box 的当前 PHP 版本,可用值:8.0 | 8.1box config get-php-version 获取 box 的当前设置的 PHP 版本box reverse-proxy -u <upsteamHost:upstreamPort> 启动一个反向代理 HTTP 服务器,用于将 HTTP 请求转发到指定的多个上游服务器box php 通过当前 box 的 PHP 版本运行任何 PHP 命令box composer 通过当前 box 的 PHP 版本运行任何 Composer 命令box php-cs-fixer 通过当前 box 的 PHP 版本运行任何 php-cs-fixer 命令box cs-fix 通过当前 box 的 PHP 版本运行 php-cs-fixer fix 命令box phpstan 通过当前 box 的 PHP 版本运行任何 phpstan 命令box pint 通过当前 box 的 PHP 版本运行任何 pint 命令更多优化Hyperf 3.0 仍做了大量的优化和调整,具体可以阅读 Hyperf 主仓库中的 CHANGELOG-3.0.md 文件。同时我们也为大家准备了一份从 2.2 升级至 3.0 的指南,具体可查阅 Hyperf 官方文档 - 3.0 升级指南 一章。相关链接Hyperf 的详细介绍:点击查看Hyperf 的下载地址:点击下载
2023年08月12日
15 阅读
0 评论
0 点赞
1
...
45
46
47
...
112