菜单

四 分析easyswoole源码(运行服务&Cache组件原理)

2019年2月17日 - 金沙编程资讯

其一艺术重假若开行swoole服务的

3 使用laravel5.5兑现的前后台通讯实例

重大思路是行使php artisan
自建命令控战胜务端,使用HTML5的websocket达成客户端功用

服务端:app/Console/Commands/Websocket.php内容

<?php

namespace App\Console\Commands;

use Illuminate\Console\Command;
use swoole_http_request;
use swoole_http_response;
use swoole_websocket_server;

class WebSocket extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'websocket 
                            {cmd=start : can use start|stop|status|restart}
                            {--daemon : set to run in daemonize mode}
                            ';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'swoole server control';


    /**
     * server
     *
     * @var swoole_websocket_server
     */
    private $server;

    /**
     *      * TYPE_ADMIN
     *           */
    const TYPE_ADMIN = 0X00;

    /**
     * Create a new command instance.
     *
     * @return void
     */
    public function __construct()
    {
        parent::__construct();
    }

    /**
     * 处理不同command信息
     *
     * @return mixed
     */
    public function handle()
    {
        $command = $this->argument('cmd');
        $option = $this->option('daemon');

        switch ($command) {
            case 'start':
                $this->initWs($option);
                break;
            case 'stop':
                $res = $this->sendAdminRequest($command);
                if ($res){
                    $this->info('stop the server successfully');
                } else {
                    $this->info('the server is not running');
                }
                break;
            case 'status':
                $res = $this->sendAdminRequest($command);
                if ($res){
                    $this->info($res);
                } else {
                    $this->info('the server is not running');
                }
                break;
            case 'restart':
                $res = $this->sendAdminRequest($command);
                if ($res){
                    $this->info('restart the server successfully');
                } else {
                    $this->info('the server is not running');
                }
                break;
            default:
                $this->info('请按照下面格式输入命令:php artisan websocket {start|stop|status|restart}');
                break;
        }

    }

    //初始化服务端
    public function initWs($daemonize = false) 
    {
        if ($daemonize) {
            $this->info('Starting Websocke server in daemon mode...');
        } else {
            $this->info('Starting Websocke server in interactive mode...');
        }

        $server = new swoole_websocket_server('0.0.0.0', 9501);
        $server->set([
            'daemonize' => $daemonize,
            'log_file' => '/var/log/websocket.log'
        ]);

        $server->on('close', function ($server, $fd) {
            $this->info('close websocket server');
        });

        $server->on('open', function (swoole_websocket_server $server, $request) {
            $this->info('websocket open');
        });

        $server->on('open', [$this, 'onOpen']);
        $server->on('close', [$this, 'onClose']);
        $server->on('message', [$this, 'onMessage']);
        $server->on('request', [$this, 'onRequest']);

        $this->server = $server;
        $this->server->start();
    }

    public function onOpen(swoole_websocket_server $server, $request) 
    {
            $this->info('websocket open');
    }

    public function onClose($server, $fd) 
    {
            $this->info('close websocket server');
    }

    public function onMessage(swoole_websocket_server $server, $frame) 
    {
        $this->info($frame->data);
        $data = json_decode($frame->data, true);

        //对data进行逻辑处理
        $reply = '发送的信息是:' . $data['message'];
        $response = [
            'status' => true,
            'data' => $reply
        ];
        $server->push($frame->fd, json_encode($response));
    }

    //websocket客户端同样支持http协议
    public function onRequest(swoole_http_request $request, swoole_http_response $response) 
    {
        if ($request->post['type'] == self::TYPE_ADMIN) {
            $ret = json_encode($this->commandHandle($request->post['content']));
            return $response->end($ret);
        }
    }

    //操作命名
    public function commandHandle($command) {
        if ($command == 'status') {
            $this->info('handle status');
            return $this->server->stats();
        }
        if ($command == 'restart') {
            $this->info('handle restart');
            return $this->server->reload();
        }
        if ($command == 'stop') {
            $this->info('handle stop');
            return $this->server->stop() && $this->server->shutdown();
        }
        return 'Unknown Command';
    }

    //发送http请求
    public function sendAdminRequest($content) {
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, "http://127.0.0.1:9501");
        curl_setopt($ch, CURLOPT_HEADER, 0);
        curl_setopt($ch, CURLOPT_POST, 1);
        curl_setopt($ch, CURLOPT_HTTPHEADER, ['Expect:']);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_POSTFIELDS, [
            'type' => self::TYPE_ADMIN,
            'content' => $content
        ]);

        $response = curl_exec($ch);
        curl_close($ch);
        return $response;
    }

}

客户端内容

<!doctype html>
<html lang="{{ app()->getLocale() }}">
    <head>
        <meta charset="utf-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>websocket client</title>
    </head>
    <body>
        <div>
            <input id="message-content" type="text" name="message" />
            <button onclick="sendMessage()">发送消息</button>
        </div>
    </body>
    <script>
        var wsServer = 'ws://115.159.81.46:9501';
        var websocket = new WebSocket(wsServer);
        websocket.onopen = function (evt) {
            console.log("Connected to WebSocket server.");
        };

        websocket.onclose = function (evt) {
            console.log("Disconnected");
        };

        websocket.onmessage = function (evt) {
            console.log('从服务器接收到json信息: ' + evt.data);
            alert('服务器返回信息:' + JSON.parse(evt.data).data);
        };

        websocket.onerror = function (evt, e) {
            console.log('Error occured: ' + evt.data);
        };

        function sendMessage(){
            var content = document.getElementById('message-content').value;
            var data = {
                message : content,
            }
            websocket.send(JSON.stringify(data));
        };
    </script>
</html>

启动websocket服务器

进去系统根目录,
php artisan websocket [–daemon] //是不是采纳daemon方式
php artisan websocket start|stop|status|restart //默认是start

Cache是以单例形式达成的。构造器会举行如下操作

因为运用swoole作为http后,这个providers会被存到内存中,所以那里配置的是历次请求都想要重新登记和另行起动的providers。

$register = new EventRegister();
$this->finalHook($register);
EasySwooleEvent::mainServerCreate($this,$register);//这里是框架全局事件mainServerCreate主服务创建事件
 $events = $register->all();
//然后循环给swoole服务器绑定回调函数。这里同一个回调方法设置多个回调函数
foreach ($events as $event => $callback){
     $this->mainServer->on($event, function () use ($callback) {
       $ret = [];
       $args = func_get_args();
       foreach ($callback as $item) {
          array_push($ret,Invoker::callUserFuncArray($item, $args));
       }
       if(count($ret) > 1){
          return $ret;
       }
       return array_shift($ret);
     });
}

1.1 安装swoole前务必有限支持系统已经设置了下列软件

php-5.3.10 或更高版本
gcc-4.4 或更高版本
make
autoconf
pcre (centos系统可以执行命令:yum install pcre-devel)

$this->run($this->swooleProcess)这么些函数是CacheProcess倘使配置了persistentTime,就会敞开2个定时器定时去取$file

Config::getInstance()->getConf(‘TEMP_DI汉兰达’).”/{$processName}.data”;的数据备份,暗中同意是0约等于不会去做定时数据落地的操作

看看此间才是Cache组件在率先次实例化的时候做的连锁事情,统计就是创设了点名数量的Cache进度绑定到swoole服务器上。在大局的process_hash_map表中能找到相应的Cache进程ID。然后Cache进度是可以以管道方式来进展通讯。

 

set缓存方法

public function set($key,$data)
{
    if(!ServerManager::getInstance()->isStart()){
        $this->cliTemp->set($key,$data);
    }
    if(ServerManager::getInstance()->getServer()){
        $num = $this->keyToProcessNum($key);
        $msg = new Msg();
        $msg->setCommand('set');
        $msg->setArg('key',$key);
        $msg->setData($data);
        ProcessManager::getInstance()->getProcessByName($this->generateProcessName($num))->getProcess()->write(\swoole_serialize::pack($msg));//直接把需要缓存的数据,封装成msg然后write给hash映射到的Cache进程
    }
}

当进度取得到的时候会回调onReceive方法

public function onReceive(string $str,...$agrs)
{
    // TODO: Implement onReceive() method.

    $msg = \swoole_serialize::unpack($str);
    $table = TableManager::getInstance()->get(Cache::EXCHANGE_TABLE_NAME);
    if(count($table) > 1900){
        //接近阈值的时候进行gc检测
        //遍历Table 依赖pcre 如果发现无法遍历table,检查机器是否安装pcre-devel
        //超过0.1s 基本上99.99%为无用数据。
        $time = microtime(true);
        foreach ($table as $key => $item){
            if(round($time - $item['microTime']) > 0.1){
                $table->del($key);
            }
        }
    }
    if($msg instanceof Msg){
        switch ($msg->getCommand()){
            case 'set':{
                $this->cacheData->set($msg->getArg('key'),$msg->getData());
                break;
            }
            case 'get':{
                $ret = $this->cacheData->get($msg->getArg('key'));
                $msg->setData($ret);
                $table->set($msg->getToken(),[
                    'data'=>\swoole_serialize::pack($msg),
                    'microTime'=>microtime(true)
                ]);
                break;
            }
            case 'del':{
                $this->cacheData->delete($msg->getArg('key'));
                break;
            }
            case 'flush':{
                $this->cacheData->flush();
                break;
            }
            case 'enQueue':{
                $que = $this->cacheData->get($msg->getArg('key'));
                if(!$que instanceof \SplQueue){
                    $que = new \SplQueue();
                    $this->cacheData->set($msg->getArg('key'),$que);
                }
                $que->enqueue($msg->getData());
                break;
            }
            case 'deQueue':{

                $que = $this->cacheData->get($msg->getArg('key'));
                if(!$que instanceof \SplQueue){
                    $que = new \SplQueue();
                    $this->cacheData->set($msg->getArg('key'),$que);
                }
                $ret = null;
                if(!$que->isEmpty()){
                    $ret = $que->dequeue();
                }
                $msg->setData($ret);
                //deQueue 有cli 服务未启动的请求,但无token
                if(!empty($msg->getToken())){
                    $table->set($msg->getToken(),[
                        'data'=>\swoole_serialize::pack($msg),
                        'microTime'=>microtime(true)
                    ]);
                }
                break;
            }
            case 'queueSize':{
                $que = $this->cacheData->get($msg->getArg('key'));
                if(!$que instanceof \SplQueue){
                    $que = new \SplQueue();
                }
                $msg->setData($que->count());
                $table->set($msg->getToken(),[
                    'data'=>\swoole_serialize::pack($msg),
                    'microTime'=>microtime(true)
                ]);
                break;
            }
        }
    }
}

此间一开头会进行缓存GC确保内存不会撑爆

set方法会直接给$this->cacheData,设置缓存值。

 

get方法相比奇特,它会去给Cache进程发送get的一声令下,然后Cache读取到命令会将值写到_Cache,Swoole_table表中。然后再去读取(这些会有1个while循环,类似自旋)出缓存内容。这样的功利,可以确保可以读取到立时的数目缓存,不会因为高并发读取到最新的缓存值内容。而且还是能更实用的做gc,避免Cache内存撑爆。

public function get($key,$timeOut = 0.01)
{
    if(!ServerManager::getInstance()->isStart()){
        return $this->cliTemp->get($key);
    }
    $num = $this->keyToProcessNum($key);
    $token = Random::randStr(9);//这个是一个凭证,是确保获取到自己此刻想获取的cache数据,和事务类似为了保证可重复读
    $process = ProcessManager::getInstance()->getProcessByName($this->generateProcessName($num));
    $msg = new  Msg();
    $msg->setArg('timeOut',$timeOut);
    $msg->setArg('key',$key);
    $msg->setCommand('get');
    $msg->setToken($token);
    $process->getProcess()->write(\swoole_serialize::pack($msg));
    return $this->read($token,$timeOut);
}

$process->getProcess()->write(\swoole_serialize::pack($msg))发这么些包给Cache进度,Cache进度会举行下边这个操作

$ret = $this->cacheData->get($msg->getArg('key'));//获取到当前的缓存值
$msg->setData($ret);
//将当前的内容设置到_Cache表中,token是请求的时候发过来的凭证原样拼装。这有什么好处呢,就是确保在高并发下,在A时刻获取的缓存,不会拿到后面B时刻更新的值。
$table->set($msg->getToken(),[
    'data'=>\swoole_serialize::pack($msg),
    'microTime'=>microtime(true)
]);

$this->read($token,$timeOut);

//这里的操作是直接从_Cache表中获取缓存数据,如果缓存存在并且进程调度没有超时,然后在表中将取过数据的内容删除掉返回
private function read($token,$timeOut)
{
    $table = TableManager::getInstance()->get(self::EXCHANGE_TABLE_NAME);
    $start = microtime(true);
    $data = null;
    while(true){
        usleep(1);
        if($table->exist($token)){
            $data = $table->get($token)['data'];
            $data = \swoole_serialize::unpack($data);
            if(!$data instanceof Msg){
                $data = null;
            }
            break;
        }
        if(round($start - microtime(true),3) > $timeOut){
            break;
        }
    }
    $table->del($token);
    if($data){
        return $data->getData();
    }else{
        return null;
    }
}

 

'providers' => [
    // App\Providers\AuthServiceProvider::class,
]

  

2 创设Swoole基本实例

addProcess($this->generateProcessName($i),CacheProcess::class);
$this->generateProcessName($i)那个代码很粗略就是基于$i来设置进度名称
addProcess 是在processList存储CacheProcess::class的实例,具体代码如下

5.使用Nginx代理

//创建主服务
$this->createMainServer();

1.2 下载并解压

下载地址
跻身页面后选用download链接下的tar.gz的压缩包
下载源代码包后,解压
tar xzvf xxx.tar.gz,
在极限进入源码目录,执行上边的指令举行编译和安装
cd swoole
phpize
./configure –enable-swoole-debug
make
sudo make install

编译参数依据自个儿的须要采用,详情参见官方文档。

TableManager::getInstance()->add(
    'process_hash_map',[
        'pid'=>[
            'type'=>Table::TYPE_INT,
            'size'=>10
        ]
    ],256
);

将计划文件导出到 config 目录下

下篇作品介绍TableManager。因为它在众多地点都被用到了。  

[toc]
swoole算是nodejs在php中的一种已毕,异步响应请求,质量超强

$key = md5($processName);
if(!isset($this->processList[$key])){
    try{

        $process = new $processClass($processName,$args,$async);
        $this->processList[$key] = $process;
        return true;
    }catch (\Throwable $throwable){
        Trigger::throwable($throwable);
        return false;
    }
}else{
    trigger_error("you can not add the same name process : {$processName}.{$processClass}");
    return false;
}

 

终极注册相关的cache监听端口等就开行swoole服务了。

1 安装准备

$this->async = $async;
$this->args = $args;
$this->processName = $processName;
$this->swooleProcess = new \swoole_process([$this,'__start'],false,2);
ServerManager::getInstance()->getServer()->addProcess($this->swooleProcess);//然后swoole服务会addProcess一个Cache的任务进程。

Laravel框架运营的时候须要加载很多文本,再拉长其出了名的生态环境好,所以在支付进程中我们就会发现有相当多的已经造好的车轱辘,那也就使得Laravel的三遍运转的磁盘IO越发高(就是要加载很多文书嘛),博主以前的五次博客Laravel5框架品质优化技术中也提到过一些优化,不过并没有实质的化解磁盘IO高的题目。

$this->finalHook($register);

//实例化对象池管理
PoolManager::getInstance();
//register,先绑定一个workerStart回调函数。此事件在Worker进程/Task进程启动时发生。这里创建的对象可以在进程全局周期内使用。
$register->add($register::onWorkerStart,function (\swoole_server $server,int $workerId){
 PoolManager::getInstance()->__workerStartHook($workerId);
 $workerNum = Config::getInstance()->getConf('MAIN_SERVER.SETTING.worker_num');
 $name = Config::getInstance()->getConf('SERVER_NAME');
 if(PHP_OS != 'Darwin'){
  if($workerId <= ($workerNum -1)){//判断当前是否是worker进程
   $name = "{$name}_Worker_".$workerId;
  }else{//这个是task进程
   $name = "{$name}_Task_Worker_".$workerId;
  }
  cli_set_process_title($name);//设置当前的进程名称
  //图片
 }
});
//EventHelper 是一个框架提供的默认的事件处理函数(这些放到后面具体讲述)
EventHelper::registerDefaultOnTask($register);//注册默认的task回调,处理task任务的具体函数
EventHelper::registerDefaultOnFinish($register);//注册默认的task任务完成后的回调
EventHelper::registerDefaultOnPipeMessage($register);//注册pipeMessage回调函数
$conf = Config::getInstance()->getConf("MAIN_SERVER");
//如果是http服务器或者websocket,需要注册request回调函数
if($conf['SERVER_TYPE'] == self::TYPE_WEB_SERVER || $conf['SERVER_TYPE'] == self::TYPE_WEB_SOCKET_SERVER){
 if(!$register->get($register::onRequest)){
  EventHelper::registerDefaultOnRequest($register);//这里包含了请求,然后路由解析,处理返回的功能。就跟一般web框架类似
 }
}  

2.1 tcp服务器实例

(来自w3cschool教程

服务端代码:Server.php

<?php
// Server
class Server
{
    private $serv;

    public function __construct() {
        $this->serv = new swoole_server("0.0.0.0", 9501);
        $this->serv->set(array(
            'worker_num' => 8,
            'daemonize' => false,
            'max_request' => 10000,
            'dispatch_mode' => 2,
            'debug_mode'=> 1
        ));

        $this->serv->on('Start', array($this, 'onStart'));
        $this->serv->on('Connect', array($this, 'onConnect'));
        $this->serv->on('Receive', array($this, 'onReceive'));
        $this->serv->on('Close', array($this, 'onClose'));

        $this->serv->start();
    }

    public function onStart( $serv ) {
        echo "Start\n";
    }

    public function onConnect( $serv, $fd, $from_id ) {
        $serv->send( $fd, "Hello {$fd}!" );
    }

    public function onReceive( swoole_server $serv, $fd, $from_id, $data ) {
        echo "Get Message From Client {$fd}:{$data}\n";
    }

    public function onClose( $serv, $fd, $from_id ) {
        echo "Client {$fd} close connection\n";
    }
}
// 启动服务器
$server = new Server();

从代码中得以看来,创立3个swoole_server基本分三步:

  1. 经过构造函数创设swoole_server对象
  2. 调用set函数设置swoole_server的相关布署选项
  3. 调用on函数设置相关回调函数
    关于set配置选项以及on回调函数的求实表明,请参考小编收拾的swoole文档(
    配置选项)
    那边只交给简单介绍。onStart回调在server运营前被调用,onConnect在有新客户端连接过来时被调用,onReceive函数在有多少发送到server时被调用,onClose在有客户端断开连接时被调用。
    那里就可以差不多看看哪些运用swoole:在onConnect处监听新的接连;在onReceive处接收数据并拍卖,然后可以调用send函数将处理结果发送出去;在onClose各处理客户端下线的风云。

客户端的代码:Client.php

<?php
class Client
{
    private $client;

    public function __construct() {
        $this->client = new swoole_client(SWOOLE_SOCK_TCP);
    }

    public function connect() {
        if( !$this->client->connect("127.0.0.1", 9501 , 1) ) {
            echo "Error: {$fp->errMsg}[{$fp->errCode}]\n";
        }
        $message = $this->client->recv();
        echo "Get Message From Server:{$message}\n";

        fwrite(STDOUT, "请输入消息:");  
        $msg = trim(fgets(STDIN));
        $this->client->send( $msg );
    }
}

$client = new Client();
$client->connect();

这里,通过swoole_client创建三个依据TCP的客户端实例,并调用connect函数向内定的IP及端口发起连接请求。随后即可通过recv()和send()三个函数来接受和殡葬请求。需求注意的是,那里小编动用了暗中认可的协同阻塞客户端,因而recv和send操作都会时有暴发网络不通。

应用办法

进入到文件目录,在窗口1先运行php
Serve.php,然后再开多少个窗口(窗口2)运行php Client.php
窗口1内容:

# root @ WENGINE in /data/learnSwoole [9:24:57] C:130
$ php Server.php
Start
Get Message From Client 1:ceshi1
Client 1 close connection

窗口2内容:

# root @ WENGINE in /data/learnSwoole [9:23:07] 
$ php Client.php
Get Message From Server:Hello 1!
请输入消息:ceshi1

ProcessManager::getInstance()这句话主要做了下边的操作
ProcessManager
的__construct构造函数成立了三个swoole_table,表名是process_hash_map

近期可以透过配备文件里的host和port去做客Laravel了,例如作者的陈设是: 127.0.0.1:1215 

Cache::getInstance(); //这里注册Cache
Cluster::getInstance()->run(); //实现RPC
CronTab::getInstance()->run(); //定时任务
$this->attachListener();//Swoole提供了swoole_server::addListener来增加监听的端口。业务代码中可以通过调用swoole_server::connection_info来获取某个连接来自于哪个端口。这里框架启动的时候host配置的是0.0.0.0 所以监听所有地址,就没必要设置这个了
$this->isStart = true;
$this->getServer()->start();//启动swoole服务器,在这之前创建的对象都在程序全局期中  

2.3 WebSocket服务器

服务端程序代码 ws_server.php

//创建websocket服务器对象,监听0.0.0.0:9502端口
$ws = new swoole_websocket_server("0.0.0.0", 9502);

//监听WebSocket连接打开事件
$ws->on('open', function ($ws, $request) {
    var_dump($request->fd, $request->get, $request->server);
    $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();

WebSocket服务器是建立在Http服务器之上的长连接服务器,客户端首先会发送多个Http的请求与服务器举办握手。握手成功后会触发onOpen事件,表示连接已就绪,onOpen函数中可以博得$request对象,包括了Http握手的连锁音信,如GET参数、Cookie、Http头音信等。
创造连接后客户端与劳务器端就可以双向通讯了。
● 客户端向劳动器端发送音讯时,服务器端触发onMessage事件回调

服务器端可以调用$server->push()向有些客户端(使用$fd标识符)发送消息
● 服务器端能够安装onHandShake事件回调来手工处理WebSocket握手
运行程序

客户端的代码

能够利用Chrome浏览器举办测试,JS代码为:

var wsServer = 'ws://127.0.0.1:9502';
var websocket = new WebSocket(wsServer);
websocket.onopen = function (evt) {
    console.log("Connected to WebSocket server.");
};

websocket.onclose = function (evt) {
    console.log("Disconnected");
};

websocket.onmessage = function (evt) {
    console.log('Retrieved data from server: ' + evt.data);
};

websocket.onerror = function (evt, e) {
    console.log('Error occured: ' + evt.data);
};

关于onRequest回调
swoole_websocket_server 继承自 swoole_http_server

可以创造更多的劳务器 参照官方文档尝试

//根据配置创建指定数目的Cache服务进程,然后启动。
$num = intval(Config::getInstance()->getConf("EASY_CACHE.PROCESS_NUM"));//默认配置数目是1,在Config.php里'EASY_CACHE.PROCESS_NUM'=>1
if($num <= 0){
   return;
}
$this->cliTemp = new SplArray();//这个数组以后会给单元测试时候单独使用,正常模式这个数组是不使用的
//若是在主服务创建,而非单元测试调用
if(ServerManager::getInstance()->getServer()){
    //创建了一个swoole_table ,表名为__Cache,里面存储data(后面就讲到其实这里存储的是操作Cache的指令)作用是用来做GC(防止Cache被撑爆)
    TableManager::getInstance()->add(self::EXCHANGE_TABLE_NAME,[
        'data'=>[
            'type'=>Table::TYPE_STRING,
            'size'=>10*1024
        ],
        'microTime'=>[
            'type'=>Table::TYPE_STRING,
            'size'=>15
        ]
    ],2048);
    $this->processNum = $num;
    for ($i=0;$i < $num;$i++){
        ProcessManager::getInstance()->addProcess($this->generateProcessName($i),CacheProcess::class);
    }
}

图片 1

开创默许的轩然大波注册器,给劳务登记暗中认同的是事件处理函数

1.3 编译安装成功后,修改php.ini

在php.ini中加入 extension=swoole.so
通过在命令行使用 php-m查看,是不是安装了swoole

只顾:如通重新编译的话须求 make clean

ProcessManager::getInstance()->addProcess($this->generateProcessName($i),CacheProcess::class)那句话才是Cache的主导逻辑。

要是你利用的是lumen,那么在 bootstrap/app.php 中插手如下代码

 在那块代码里根本是骨干,是在swoole执行start服务前安装相关配置以及配备相关回调函数。具体代码如下

2.2 web服务器

服务端代码 http_server.php

$http = new swoole_http_server("0.0.0.0", 9501);

$http->on('request', function ($request, $response) {
    var_dump($request->get, $request->post);
    $response->header("Content-Type", "text/html; charset=utf-8");
    $response->end("<h1>Hello Swoole. #".rand(1000, 9999)."</h1>");
});

$http->start();

Http服务器只需要关爱请求响应即可,所以只须求监听多少个onRequest事件。当有新的Http请求进入就会触发此事件。事件回调函数有1个参数,多少个是$request对象,包涵了请求的连带新闻,如GET/POST请求的数码。
此外一个是response对象,对request的响应得以通过操作response对象来成功。$response->end()方法表示输出一段HTML内容,并甘休此呼吁。
● 0.0.0.0
表示监听全体IP地址,一台服务器大概同时有七个IP,如127.0.0.1地点回环IP、192.168.1.100局域网IP、210.127.20.2
外网IP,那里也可以独自指定监听2个IP
● 9501 监听的端口,假如被占用程序会抛出致命错误,中断执行。

那么CacheProcess::class的实例话做了哪些操作呢
$this->cacheData = new
SplArray();//那里很重大,为何这么说每一种Cache进度实际保存的缓存值都以在那里的,各种Cache进度都有温馨的贰个cacheData数组
$this->persistentTime =
Config::getInstance()->getConf(‘EASY_CACHE.PERSISTENT_TIME’);
parent::__construct($processName, $args);
CacheProcess::class继承于AbstractProcess
AbstractProcess的构造方法

 swoole_http.php 里还提供配置 providers 数组,

前文连接,阅读的时候最好参照EasySwoole2.1.2的源码

前文提到的在系统安装Cache组件
Cache::getInstance()的时候,会去调用processManager去创建Cache的长河,然后以管道通讯的艺术进行设置缓存和取得缓存。

至此,马到成功,你可以像日常一样访问你的网站了。

$conf = Config::getInstance()->getConf("MAIN_SERVER");//获取Config.php 中配置的MAIN_SERVER数组
$runModel = $conf['RUN_MODEL'];//获取运行模式 默认是SWOOLE_PROCESS模式,使用进程模式,业务代码在Worker进程中执行
$host = $conf['HOST'];//获取运行的host 'HOST'=>'0.0.0.0',
$port = $conf['PORT'];//获取配置的运行端口为9501 'PORT'=>9501,
$setting = $conf['SETTING'];//这里设置的相关的配置项,这些配置做一些解释,参照https://wiki.swoole.com/wiki/page/274.html
'SETTING'=>[
         'task_worker_num' => 8, //配置Task进程的数量,配置此参数后将会启用task功能。所以Server务必要注册onTask、onFinish2个事件回调函数。如果没有注册,服务器程序将无法启动。
         'task_max_request'=>10,//设置task进程的最大任务数。一个task进程在处理完超过此数值的任务后将自动退出。这个参数是为了防止PHP进程内存溢出。如果不希望进程自动退出可以设置为0,炒鸡重要,进程中的数据,如果有一个global数组,或者全局变量,不设置这个就会不回收最终导致内存溢出
         'max_request'=>5000,//设置worker进程的最大任务数,这个和task_max_request功能一样,为了解决PHP进程内存溢出问题
         'worker_num'=>8//设置启动的Worker进程数
       ],
//其实这里还有2个配置,是前文中提到的,在前文19行$this->sysDirectoryInit();会初始化配置pid_file和log_file
pid_file //在Server启动时自动将master进程的PID写入到文件,在Server关闭时自动删除PID文件。
log_file //指定swoole错误日志文件。在swoole运行期发生的异常信息会记录到这个文件中。默认会打印到屏幕。
$sockType = $conf['SOCK_TYPE'];//指定当前运行的服务是什么服务器。有tcp服务,http服务,websocket服务。默认是tcp服务
switch ($conf['SERVER_TYPE']){
  case self::TYPE_SERVER:{
    $this->mainServer = new \swoole_server($host,$port,$runModel,$sockType);//创建mainServer,这里创建了一个tcp服务器
       break;
   }
  case self::TYPE_WEB_SERVER:{
    $this->mainServer = new \swoole_http_server($host,$port,$runModel,$sockType);//web方式是默认
       break;
   }
  case self::TYPE_WEB_SOCKET_SERVER:{
       $this->mainServer = new \swoole_websocket_server($host,$port,$runModel,$sockType);
       break;
   }
  default:{
    Trigger::throwable(new \Exception("unknown server type :{$conf['SERVER_TYPE']}"));
  }
}
$this->mainServer->set($setting);//将上面的相关服务启动配置到mainServer
if(PHP_OS != 'Darwin'){
    $process->name($this->getProcessName());
}
TableManager::getInstance()->get('process_hash_map')->set(
    md5($this->processName),['pid'=>$this->swooleProcess->pid]
);
ProcessManager::getInstance()->setProcess($this->getProcessName(),$this);
if (extension_loaded('pcntl')) {
    pcntl_async_signals(true);
}
Process::signal(SIGTERM,function ()use($process){
    $this->onShutDown();
    TableManager::getInstance()->get('process_hash_map')->del(md5($this->processName));
    swoole_event_del($process->pipe);
    $this->swooleProcess->exit(0);
});
if($this->async){
    swoole_event_add($this->swooleProcess->pipe, function(){
        $msg = $this->swooleProcess->read(64 * 1024);
        $this->onReceive($msg);
    });
}
$this->run($this->swooleProcess);

swoole在官网也涉及过:swoole_http_server对Http协议的支撑并不完整,建议仅作为应用服务器。并且在前者增加Nginx作为代理。

$inst->run();//启动服务

__start方法紧假设给swoole_table,表名为process_hash_map插入当前CacheProcess的经过名为key,进度IDpid为value。并且注册进度退出的风浪。

1.是怎么样范围Laravel框架的快慢?

相关文章

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图