在继续上一章讲完了Tcp服务端对讲之后,本章介绍一个使用swoole_http_server的对象池demo.
优点如下:
- 对象常驻内存,不必每次new去实例化一个对象.
- 定时清除对象池用不到的对象。
- 对小白友好的表达面向对象式Swoole编程原理.
开始:
根据 swoole wiki介绍, swoole_http_server是继承自 swoole_server .
简单服务器构造如下:
class Server {
protected $server ;
protected $config ;
public function __construct($config)
{
$this->config = $config ;
$this->server = new swoole_http_server($config['host'], $config['port']);
$this->setConfig();
}
protected function setConfig()
{
$this->server->set($this->config['server']);
}
public function run()
{
$this->server->on('request',[$this, 'onRequest']);
}
public function onRequest($request ,$response)
{
// todo
}
}
$config = ['server' => ['worker_num' => 4 , "task_worker_num" => "20" , "dispatch_mode" => 3 ] , 'host' => '0.0.0.0' , 'port' => 9501];
$server = new Server($config);
$server->run();
onRequest 方法就是我们要处理请求的地方了.
- 传统方法
在onRequest里边根据请求的request_uri计算出路由,根据路由实例化控制器.
public function onRequest($request ,$response)
{
$router = new Router($request);
$controller = $router->getController();// 控制器
$action = $router->getAction(); //方法
$resp = $controller->{$action}();
$response->end($resp);
}
可以看出这种做法对象复用率不好。
- 对象池的做法:
对象池原理:
namespace Factory;
class ControllerFactory
{
/**
* @var \Factory\ControllerFactory
*/
public static $instance ;
private $pool ;
public function __construct( )
{
self::$instance = $this ;
}
public static function getInstance()
{
if(is_null(self::$instance))
{
new ControllerFactory();
}
return self::$instance;
}
/**
* 从对象池获取一个对象,
* @param $class
* @return \Controller\Controller
*/
public function getController($class)
{
if (isset($this->pool[$class]))
{
if(count($this->pool[$class]) > 0)
{
$controller = $this->pool[$class]->shift();
$controller->init();
$controller->poolName = $class ;
return $controller ;
}
}
else{
$this->pool [$class] = new \SplQueue();
}
if (!class_exists($class)){
throw new \RuntimeException("class not found :: {$class}");
}
$object = new $class;
return $object ;
}
/**
* 返回对象给对象池
* @param $controller
*/
public function giveBack($controller)
{
if ($controller->destory())
{
$this->pool[$controller->poolName]->push($controller);
}
}
/**
* 用于打印输出对象池的对象以及个数
*/
public function count()
{
if(is_null($this->pool))
{
return ;
}
echo "========对象池计算开始=======" , "\n";
echo "对象类型总数:" . count($this->pool) , "\n";
foreach ($this->pool as $key => $object) {
echo "对象:{$key} , " . "个数:" . count($object) . "\n";
}
echo "========对象池计算结束=======" , "\n";
}
}
上下文对象是对请求以及响应的封装
use Factory\ControllerFactory;
class Context
{
private $request ;
private $response ;
private $hasOver ;
private $controller ;
public function __construct($request , $response,$controller)
{
$this->request = $request ;
$this->response = $response ;
$this->hasOver = false ;
$this->controller = $controller ;
}
public function send($string)
{
if($this->over())
{
return ;
}
$this->setResponseStatus(200);
$this->hasOver = true ;
$this->response->end($string);
ControllerFactory::getInstance()->giveBack($this->controller);
}
public function setResponseStatus(int $status)
{
if($this->over())
{
return ;
}
$this->response->status($status);
}
public function setResponseHeader($key,$value)
{
if($this->over())
{
return ;
}
$this->response->header($key , $value);
}
public function over()
{
return $this->hasOver ;
}
}
请求过程:
function onRequest($request, $response)
{
// 解析路由 .
$router = trim($request->server ['request_uri'] , '/') ;
try{
if($router == 'favicon.ico')
{
$response->end('');
return ;
}
if($router == '' )
{
// todo 首页地址 .
$response->end('index ...');
return ;
}
$routerArr = explode('/' ,$router);
if(count($routerArr) == 1)
{
$controller = ucfirst($routerArr [0]) ;
$method = "index";
}
else{
$controller = ucfirst($routerArr [0]);
$method = $routerArr [1];
}
// todo 大于 2段 / 的地址
// 组装controller & router .
$controllerNamespace = "Controller\\{$controller}Controller";
$controllerObject = ControllerFactory::getInstance()->getController($controllerNamespace);
$controllerObject->setContext(new Context($request,$response,$controllerObject));
if(!method_exists($controllerObject , $method))
{
throw new \RuntimeException("method not found :: {$controllerNamespace}::$method()");
}
$controllerObject->{$method}();
}
catch (\Exception $exception) {
$response->status(500);
$response->end('server error ::' . $exception->getMessage());
}
return ;
}
如有错误,敬请纠正!
本代码已托管到github: clearcodecn/swoole-demo
另外:clearcode.cn是本人正在建设中的一个社区,旨在讲解服务器端技术与原理,提倡开源精神,授人以鱼不如授人以渔,由于时间不足,导致进展缓慢,希望有兴趣的朋友一起加入.
QQ群: 139348611
转载请申明来源!
路人张:Swoole-Demo(1) TCP服务端简单实现zhuanlan.zhihu.com