PHP之高性能I/O框架:Libevent(三)


Swoole

Swoole里也提供了一些直接操作底層epoll/kqueue事件循環的接口,可將其他擴展創建的socket、PHP代碼中stream/socket擴展創建的socket等加入到Swoole的EventLoop中。

文檔:https://wiki.swoole.com/wiki/page/242.html

這里我也簡單介紹一下。

基本使用

swoole_tcp_server.php

<?php 
/**
 * Created by PhpStorm.
 * User: 公眾號: 飛鴻影的博客(fhyblog)
 * Date: 2018/6/30
 */

use Swoole\Event;

$socket = stream_socket_server ("tcp://0.0.0.0:9201", $errno, $errstr);
if (false === $socket ) {
    echo "$errstr($errno)\n";
    exit();
}
if (!$socket) die($errstr."--".$errno);
// stream_set_blocking($socket,0); //可以去掉,沒有涉及到read這個socket

echo "waiting client...\n";


//accept事件回調函數,參數分別是$fd
function ev_accept($socket){
    global $master;

    $connection = stream_socket_accept($socket);

    //參數的設置將會影響到像 fgets() 和 fread() 這樣的函數從資源流里讀取數據。 
    //在非阻塞模式下,調用 fgets() 總是會立即返回;而在阻塞模式下,將會一直等到從資源流里面獲取到數據才能返回。
    stream_set_blocking($connection, 0);//如果不設置,后續讀取會阻塞
    $id = (int)$connection;

    echo "new Client $id\n";

    Event::add($connection, 'ev_read', null, SWOOLE_EVENT_READ); 
}

//read事件回調函數,參數是fd
function ev_read($buffer)
{
    $receive = '';

    //循環讀取並解析客戶端消息
    while( 1 ) {
        $read = @fread($buffer, 2);

        //客戶端異常斷開
        if($read === '' || $read === false){
            break;
        }

        $pos = strpos($read, "\n");
        if($pos === false)
        {
            $receive .= $read;
            // echo "received:".$read.";not all package,continue recdiveing\n";
        }else{
            $receive .= trim(substr ($read,0,$pos+1));
            $read = substr($read,$pos+1);
            
            switch ( $receive ){
                case "quit":
                    echo "client close conn\n";
                    
                    //關閉客戶端連接
                    Event::del($buffer);//刪除事件
                    fclose($buffer);//斷開客戶端連接
                    break;
                default:
                    // echo "all package:\n";
                    echo $receive."\n";
                    break;
            }
            $receive='';
        }
    }
}

Event::add($socket, 'ev_accept', null, SWOOLE_EVENT_READ); 
echo  "start run...\n";

//進入事件循環
Event::wait(); //PHP5.4或更高版本不需要加此函數

//下面這句不會被執行
echo "This code will not be executed.\n";

Event::add()等方法也有對應的函數,例如swoole_event_add()

定時器

swoole提供了兩個定時器:

  • swoole_timer_tick 周期定時器,面向對象寫法:Timer::tick
  • swoole_timer_after 一次性定時器,面向對象寫法:Timer::after

swoole定時器的精度是毫秒。

示例:

<?php 
/**
 * Created by PhpStorm.
 * User: 公眾號: 飛鴻影的博客(fhyblog)
 * Date: 2018/6/30
 */

use Swoole\Timer;

Timer::after(1000, function(){
    echo time(). " hello\n";
    Timer::tick(1000, function($timer_id, $params){
        static $c = 0;
        echo time(). " hello $params $c\n";

        $c++;
        if($c > 5){
            Timer::clear($timer_id);
        }
    }, 'this is param');
});

說明:Timer::after回調函數沒有參數,Timer::tick回調函數參數是定時器ID及附加參數。

總結

我曾經查閱了Workerman的源碼,看到作者把常見的Event(系統自帶Select、libevet、Event、Ev、Swoole)進行了一次封裝,對外暴露了統一的接口(add、del、loop),大家有興趣可以看看。

參考

1、php libevent擴展的簡單用例 - NickBai - 博客園
https://www.cnblogs.com/nickbai/articles/6197689.html
2、PHP使用pcntl和libevent 實現Timer功能 | 博客水木
http://www.4u4v.net/php-uses-pcntl-and-libevent-achieve-timer-function.html
3、socket服務的模型以及實現(4)–單進程IO復用libevent
http://www.xtgxiso.com/socket服務的模型以及實現4-單進程io復用libevent/
4、libevent中的bufferevent原理 - nengm - 博客園
https://www.cnblogs.com/nengm1988/p/8203784.html
5、EventLoop-Swoole-Swoole文檔中心
https://wiki.swoole.com/wiki/page/242.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM