1.1 面向过程方案
<?php /** * Created by PhpStorm. * User: baidu * Date: 18/2/28 * Time: 上午1:39 */ $http = new swoole_http_server("0.0.0.0", 9501); $http->set([ 'worker_num' => 5, ]); $http->on('WorkerStart', function(swoole_server $server, $worker_id) { // 定义应用目录 define('APP_PATH', __DIR__ . '/../../application/'); // 加载框架里面的文件 require __DIR__ . '/../base.php'; //require __DIR__ . '/../thinkphp/start.php'; }); $http->on('request', function($request, $response) use($http){ $_SERVER = []; if(isset($request->server)) { foreach($request->server as $k => $v) { $_SERVER[strtoupper($k)] = $v; } } if(isset($request->header)) { foreach($request->header 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; } } ob_start(); // 执行应用并响应 think\Container::get('app', [APP_PATH])->run()->send(); // echo "-action-".request()->action().PHP_EOL; $res = ob_get_contents(); ob_end_clean(); $response->end($res); // $http->close($http->fd); }); $http->start();
onWorkerStart:
此事件在Worker
进程/Task
进程启动时发生,这里创建的对象可以在进程生命周期内使用
在onWorkerStart
中加载框架的核心文件后:
- 不用每次请求都加载框架核心文件,提高性能
- 可以在后续的回调事件中继续使用框架的核心文件或者类库
结果展示:(监听9501端口,路由需要配置,暂时用s=url 的方式.)
thinkphp5.1核心版本源码修改
修改ThinkPHP5
框架Request.php
源码位置:/thinkphp/library/think/Request.php
修改如下:
function path() { }
//注销判断,不再复用类成员变量$this->path
function pathinfo() { }
//注销判断,不再复用类成员变量$this->pathinfo
- 使其支持
pathinfo
路由,添加如下代码在function pathinfo() { }
中
if (isset($_SERVER['PATH_INFO']) && $_SERVER['PATH_INFO'] != '/') {
return ltrim($_SERVER['PATH_INFO'], '/');
}
完整的
Request.php
/** * 获取当前请求URL的pathinfo信息(含URL后缀) * @access public * @return string */ public function pathinfo() { if (isset($_SERVER['PATH_INFO']) && $_SERVER['PATH_INFO'] != '/') { return ltrim($_SERVER['PATH_INFO'], '/'); } // if (is_null($this->pathinfo)) { if (isset($_GET[$this->config->get('var_pathinfo')])) { // 判断URL里面是否有兼容模式参数 $_SERVER['PATH_INFO'] = $_GET[$this->config->get('var_pathinfo')]; unset($_GET[$this->config->get('var_pathinfo')]); } elseif ($this->isCli()) { // CLI模式下 index.php module/controller/action/params/... $_SERVER['PATH_INFO'] = isset($_SERVER['argv'][1]) ? $_SERVER['argv'][1] : ''; } // 分析PATHINFO信息 if (!isset($_SERVER['PATH_INFO'])) { foreach ($this->config->get('pathinfo_fetch') as $type) { if (!empty($_SERVER[$type])) { $_SERVER['PATH_INFO'] = (0 === strpos($_SERVER[$type], $_SERVER['SCRIPT_NAME'])) ? substr($_SERVER[$type], strlen($_SERVER['SCRIPT_NAME'])) : $_SERVER[$type]; break; } } } $this->pathinfo = empty($_SERVER['PATH_INFO']) ? '/' : ltrim($_SERVER['PATH_INFO'], '/'); // } return $this->pathinfo; } /** * 获取当前请求URL的pathinfo信息(不含URL后缀) * @access public * @return string */ public function path() { //注销判断,不再复用类成员变量$this->path // if (is_null($this->path)) { $suffix = $this->config->get('url_html_suffix'); $pathinfo = $this->pathinfo(); if (false === $suffix) { // 禁止伪静态访问 $this->path = $pathinfo; } elseif ($suffix) { // 去除正常的URL后缀 $this->path = preg_replace('/\.(' . ltrim($suffix, '.') . ')$/i', '', $pathinfo); } else { // 允许任何后缀访问 $this->path = preg_replace('/\.' . $this->ext() . '$/i', '', $pathinfo); } // } return $this->path; }
1.2面向对象方案
class Http { CONST HOST = "0.0.0.0"; CONST PORT = 9911; public $http = null; public function __construct() { $this->http = new swoole_http_server(self::HOST, self::PORT); $this->http->set( [ 'enable_static_handler' => true, 'document_root' => "/home/wwwroot/swoole/thinkphp/public/static", 'worker_num' => 4, ] ); $this->http->on("workerstart", [$this, 'onWorkerStart']); $this->http->on("request", [$this, 'onRequest']); $this->http->on("close", [$this, 'onClose']); $this->http->start(); } /** * 此事件在Worker进程/Task进程启动时发生,这里创建的对象可以在进程生命周期内使用 * 在onWorkerStart中加载框架的核心文件后 * 1.不用每次请求都加载框架核心文件,提高性能 * 2.可以在后续的回调中继续使用框架的核心文件或者类库 * * @param $server * @param $worker_id */ public function onWorkerStart($server, $worker_id) { // 定义应用目录 define('APP_PATH', __DIR__ . '/../../../../application/'); // 加载框架里面的文件 require __DIR__ . '/../../../../thinkphp/base.php'; } /** * request回调 * 解决上一次输入的变量还存在的问题例:$_SERVER = [] * @param $request * @param $response */ public function onRequest($request, $response) { $_SERVER = []; if(isset($request->server)) { foreach($request->server as $k => $v) { $_SERVER[strtoupper($k)] = $v; } } if(isset($request->header)) { foreach($request->header 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; } } $_POST['http_server'] = $this->http; ob_start(); // 执行应用并响应 try { think\Container::get('app', [APP_PATH]) ->run() ->send(); }catch (\Exception $e) { // todo } $res = ob_get_contents(); ob_end_clean(); $response->end($res); } /** * close * @param $ws * @param $fd */ public function onClose($ws, $fd) { echo "clientid:{$fd}\n"; } } new Http();
1.3分发Task异步任务机制实现
<?php
/**
* socket面向对象的编译
*/
class Ws
{
CONST HOST='0.0.0.0';
CONST PORT='9501';
public $ws=null;
public function __construct()
{
$this->ws=new swoole_http_server(self::HOST,self::PORT);
$this->ws->set([
//启动task必须要设置其数量
'worker_num' => 4,
'task_worker_num' => 4,
]);
$this->ws->on('workerStart',[$this,'onWorkerStart']);
$this->ws->on('request',[$this,'onRequest']);
$this->ws->on('task',[$this,'onTask']);
$this->ws->on('finish',[$this,'onFinish']);
$this->ws->on('close',[$this,'onclose']);
$this->ws->start();
}
/**
监听开启事件的回调
*/
public function onWorkerStart($server, $worker_id)
{
// 定义应用目录
define('APP_PATH', __DIR__ . '/../application/');
// 加载框架里面的文件
require __DIR__ . '/../thinkphp/base.php';
}
/**
* request回调
* @param $request
* @param $response
*/
public function onRequest($request, $response) {
$_SERVER = [];
if(isset($request->server)) {
foreach($request->server as $k => $v) {
$_SERVER[strtoupper($k)] = $v;
}
}
if(isset($request->header)) {
foreach($request->header 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;
}
}
$_POST['http_server'] = $this->ws;
ob_start();
// 执行应用并响应
try {
think\Container::get('app', [APP_PATH])
->run()
->send();
}catch (\Exception $e) {
// todo
}
$res = ob_get_contents();
ob_end_clean();
$response->end($res);
}
/**
监听关闭事件的回调
*/
public function onclose($ser, $fd)
{
print_r("你好,我的{$fd}\n");
}
/**
* $serv 服务
* $task_id 任务ID,由swoole扩展内自动生成,用于区分不同的任务
* $src_worker_id $task_id和$src_worker_id组合起来才是全局唯一的,不同的worker进程投递的任务ID可能会有相同
* $data 是任务的内容
*/
public function onTask($serv,$task_id,$src_worker_id,$data)
{
//在终端输出
print_r($data).'/n';
//执行耗时任务
sleep(10);
//回调于onFinish
return '你成了-A';
}
/**
* $task_id 是任务的ID
* $data 是任务处理的结果内容
*/
public function onFinish($serv,$task_id,$data)
{
print_r($data).'/n';
}
}
new Ws();
控制器中,千万不要再系统默认加载的控制器下写task,否则你就会发现多执行了一次任务,切记!切记!切记!
控制器:
<?php namespace app\index\controller; class Index { public function index() { $data='我是分发任务'; $a=$_POST['http_server']->task($data); echo $a.PHP_EOL; return 123; } public function a() { $data='我是分发任务aaaaaa'; $a=$_POST['http_server']->task($data); return 123456798; } public function bbb() { return 1111111111111111; } }
结果展示: