点击上方蓝字关注我们!
Swoole简介
Swoole是一个面向生产环境的 PHP 异步网络通信引擎。使 PHP 开发人员可以编写高性能的异步并发 TCP、UDP、Unix Socket、HTTP,WebSocket 服务。
Swoole扩展是按照PHP标准扩展构建的。使用phpize来生成编译检测脚本,./configure来做编译配置检测,make进行编译,make install进行安装。
Swoole实际上是一个网络通信和异步io的引擎,一个基础库。php与外部通信需要借助系统的socket,通常使用的Apache nginx就是封装了的socket,可以实现并发处理。客户端发送请求到nginx/apache,再转发到fastcgi端口交给php处理;Swoole把系统的socket集成到php底层,php可以直接通过swoole与客户端交互。也就是说Swoole是个封装了底层socket的网络库,解决异步处理、长连接、并发处理任务等。
Swoole与传统php开发的区别
1.PHP的运行模式
PHP有多种运行模式,常见的Fast-CGI,PHP-FPM模式我们归纳为传统的web模式,还有一种模式属于命令行模式:PHP-Cli
2.Swoole开发的程序和传统的php程序区别
因为使用swoole拓展的PHP脚本与传统的PHP脚步不同,前者是需要预先在服务端执行的,而后者是每次访问时才会执行。
① 比如你的程序中定义了一个类A,那么在每次有用户访问时,类A都需要提前编译到内存中,1万次访问就要编译1万次。而用swoole拓展则只需要在服务端编译一次,无论多少次访问都不需要再次编译了,只要swoole的进程存在,类A就会一直存在于内存中。
② 比如PHP入门时就必须要掌握的session,对于运用了swoole扩展的PHP程序而言,完全可以用一个变量来替换。
③ 平时写PHP代码,完全不必担心内存使用,全局变量/函数/对象等,可以随便使用,因为PHP脚本执行结束后,内存自然会自行释放掉。但用swoole扩展的PHP程序,则必然要手动注销全局的变量/函数/对象等,这就考验了PHPer的闭包能力等。
Thinkphp5集成Swoole
think-swoole2.0支持thinkphp5.0
think-swoole3.0支持thinkphp6.0
推出的tp6.0,已经适配swoole.并推出think-swoole 3.0,并且默认适配了socketio。和2.0版本在使用方法上面有些许不同。
Websocket 继承于Http,进行websocket连接之前需要一次HTTP请求,如果当期地址支持websocket则返回101,然后进行连接。也就是说并不是我的服务支持websocket后,请求每个连接地址都可以进行websocket连接,而是需要预先适配才可以连接,tp提供的组件刚开始不建议使用,等自己写熟悉了后再研究。
01
TP5的运行机制
任何请求都会经过tp5的入口文件,载入框架的配置文件,启动进程,然后处理请求。
在这个index.php的入口文件中,可以看到,它先定义的APP_PATH这个常量,然后引入的框架的启动文件start.php,那我们就去看下start.php这个文件做了些什么。
在这里,它先加载了基础文件base.php,然后启动框架run,这个时候就开始处理请求了。常规的nginx,Apache服务器,每次请求来到thinkphp,会清除静态变量,重新加载配置文件。但是Swoole做的服务器,是常驻进程,在启动服务后,会产生多个进程,来处理请求。我们要让它选择性的加载配置。
02
Swoole来做http服务器
<?php
/**
* Created by PhpStorm.
* User: 360zhiliangxiaoneng
* Date: 2019/10/21
* Time: 15:09
*/
$http = new swoole_http_server("0.0.0.0", 9501);
$http->set(
[
'enable_static_handler' => true,
'document_root' => "/var/www/thinkphp_5.0.11/public/static",
'worker_num' => 5,//产生进程的个数
]
);
$http->on('WorkerStart',function (swoole_server $server,$worker_id){
define('APP_PATH', __DIR__ . '/../application/');
// 这里 引入 base.php 而不引入start.php 是因为
// start.php 的话 就会执行thinkphp 的相应的控制器方法了
require __DIR__ . '/../thinkphp/base.php';
});
$http->on('request', function($request, $response) use($http) {
$_SERVER=[];
if(isset($request->header)){
foreach ($request->header as $k=>$v){
$_SERVER[strtoupper($k)] = $v;
}
}
if(isset($request->server)){
foreach ($request->server as $k=>$v){
$_SERVER[strtoupper($k)] = $v;
}
}
$_GET = [];
if(isset($request->get)){
foreach ($request->get as $k=>$v){
$_GET[$k] = $v;
}
}
$_POST = [];
if(isset($request->post)){
foreach ($request->post as $k=>$v){
$_POST[$k] = $v;
}
}
// print_r($_SERVER);
//开启缓存
ob_start();
try{
// 执行应用并响应
//think\Container::get('app', [APP_PATH])->run()->send();
think\App::run()->send();
}catch (\Exception $e){
}
$res = ob_get_contents();
ob_end_clean();
$response->header('Content-Type', 'text/html;charset=utf-8', false);
$response->end($res);
//$http->close();
});
$http->start();
-
$http->onWorkerStart:启动进程的时候,加载thinkphp的框架文件,base.php,但是这个时候,不能run,等待请求来了再去run。
-
$http->onrequest:当收到客户端的请求时,把Swoole的header头信息,server信息,get数据,post数据等消息转化为常规的$_SERVER,$_GET等信息,可以适配tp5。
-
最后开始run,这个时候需要把run得到的信息加载到缓存,然后再通过send()返回给客户端。
03
Swoole适配thinkphp5
因为swoole是常驻进程,前一个请求的$_POST,$_GET请求不会销毁,原因这个进程并没有kill,这个时候,需要在接收请求的时候,将$_GET,$_POST置空。swoole路由机制,总会从缓存中获取有没有这个请求,如果有,就不加载新的,所以,swoole常驻内存,会发现一直请求第一个url。除非重启swoole服务器。
在Thinkphp框架里面,修改Request文件,将两个方法(pathinfo,path)里面的$this->path这个为空的判断去掉,让每次请求都去解析这个url。
以上总结了Swoole是什么、Swoole与PHP开发的区别、Thinkphp5 如何集成 Swoole,希望读者关注公众号交流讨论。