亚洲国产日韩欧美一区二区三区,精品亚洲国产成人av在线,国产99视频精品免视看7,99国产精品久久久久久久成人热,欧美日韩亚洲国产综合乱

Table of Contents
推薦(免費(fèi)):Swoole框架" >推薦(免費(fèi)):Swoole框架
前言
安裝
基于TCP的郵件服務(wù)器
基于WebSocket多房間聊天功能
基于HTTP的簡易框架
總結(jié)
Home PHP Framework Swoole Introducing a simple implementation example of Swoole

Introducing a simple implementation example of Swoole

Dec 11, 2020 pm 05:43 PM
swoole

Swoole框架欄目介紹介紹Swoole的簡單運(yùn)用實(shí)現(xiàn)例子

Introducing a simple implementation example of Swoole

推薦(免費(fèi)):Swoole框架

前言

我們使用PHP開發(fā)WEB應(yīng)用基本都是使用傳統(tǒng)的LAMP/LNMP模式來提供HTTP服務(wù),這種模式一般是同步且堵塞的,若我們想使用PHP開發(fā)一些高級(jí)的特性(例如:異步,非堵塞,網(wǎng)絡(luò)服務(wù)器等),那么Swoole無疑是最佳的選擇,那什么是Swoole呢?

PHP的異步、并行、高性能網(wǎng)絡(luò)通信引擎,使用純C語言編寫,提供了 PHP語言的異步多線程服務(wù)器, 異步TCP/UDP網(wǎng)絡(luò)客戶端, 異步MySQL, 異步Redis, 數(shù)據(jù)庫連接池, AsyncTask, 消息隊(duì)列, 毫秒定時(shí)器, 異步文件讀寫, 異步DNS查詢。 Swoole內(nèi)置了 Http/WebSocket服務(wù)器端/ 客戶端、 Http2.0服務(wù)器端/ 客戶端。

簡單的來說,Swoole是一個(gè)PHP擴(kuò)展,實(shí)現(xiàn)了網(wǎng)絡(luò)層的很多功能,應(yīng)用場(chǎng)景非常廣,下面列舉幾個(gè)例子簡單介紹一下Swoole的應(yīng)用。

安裝

按照官方文檔進(jìn)行安裝:Swoole官網(wǎng),安裝完后使用命令:

php -m

查看是否安裝成功。注意:Swoole從2.0版本開始支持了內(nèi)置協(xié)程,需使用PHP7。

基于TCP的郵件服務(wù)器

使用Swoole提供TCP服務(wù),異步任務(wù)發(fā)送郵件。

郵件功能:

PHPMailer

PHP主代碼:

<?php

$object = new MailServer();

$setting = [
    &#39;log_file&#39; => &#39;swoole.log&#39;,
    &#39;worker_num&#39; => 4, // 4個(gè)工作進(jìn)程
    &#39;task_worker_num&#39; => 10, // 10個(gè)任務(wù)進(jìn)程
];
$server = new swoole_server("127.0.0.1", 9501);
$server->set($setting);

$server->on(&#39;WorkerStart&#39;, array($object, &#39;onWorkerStart&#39;));
$server->on(&#39;Connect&#39;, array($object, &#39;onConnect&#39;));
$server->on(&#39;Receive&#39;, array($object, &#39;onReceive&#39;));
$server->on(&#39;Close&#39;, array($object, &#39;onClose&#39;));
$server->on(&#39;Task&#39;, array($object, &#39;onTask&#39;));
$server->on(&#39;Finish&#39;, array($object, &#39;onFinish&#39;));

$server->start();

class MailServer
{
    /** @var Mail */
    private $handle;

    public function __construct()
    {
        require &#39;Mail.php&#39;; // PHPMailer郵件服務(wù)類
    }

    public function onWorkerStart($server, $workerId)
    {
        $mailConfig = require &#39;MailConfig.php&#39;; // 發(fā)件人信息,重啟時(shí)會(huì)重新加載配置文件
        $this->handle = new Mail($mailConfig);
    }

    public function onConnect($server, $fd, $reactorId)
    {

    }

    public function onReceive($server, $fd, $reactorId, $data)
    {
        $return = [];
        $dataArr = json_decode($data, true);
        if (empty($dataArr) || empty($dataArr[&#39;address&#39;]) || empty($dataArr[&#39;subject&#39;]) || empty($dataArr[&#39;body&#39;])) {
            $return[&#39;code&#39;] = -1;
            $return[&#39;msg&#39;] = &#39;參數(shù)不能為空&#39;;
        } else { // 參數(shù)校驗(yàn)成功
            $server->task($data); // 投遞一個(gè)任務(wù)
            $return[&#39;code&#39;] = 0;
            $return[&#39;msg&#39;] = &#39;投遞任務(wù)成功&#39;;
        }
        $server->send($fd, json_encode($return));
    }

    public function onTask($server, $taskId, $workerId, $data)
    {
        $data = json_decode($data, true);
        $this->handle->send($data[&#39;address&#39;], $data[&#39;subject&#39;], $data[&#39;body&#39;]); // 發(fā)送郵件
    }

    public function onFinish($server, $task_id, $data)
    {

    }

    public function onClose($server, $fd, $reactorId)
    {

    }
}

發(fā)件人信息配置:

<?php

// 郵件發(fā)送人信息配置

return [
    &#39;host&#39; => &#39;smtp.qq.com&#39;,
    &#39;port&#39; => &#39;465&#39;,
    &#39;fromName&#39; => &#39;Mr.litt&#39;,
    &#39;username&#39; => &#39;137057181@qq.com&#39;,
    &#39;password&#39; => &#39;&#39;,
];

PHPMailer郵件服務(wù)類:

<?php

require &#39;vendor/phpmailer/phpmailer/src/Exception.php&#39;;
require &#39;vendor/phpmailer/phpmailer/src/PHPMailer.php&#39;;
require &#39;vendor/phpmailer/phpmailer/src/SMTP.php&#39;;

use PHPMailer\PHPMailer\PHPMailer;

class Mail
{
    private $host;
    private $port;
    private $fromName;
    private $username;
    private $password;

    public function __construct($config)
    {
        !empty($config[&#39;host&#39;]) && $this->host = $config[&#39;host&#39;];
        !empty($config[&#39;port&#39;]) && $this->port = $config[&#39;port&#39;];
        !empty($config[&#39;fromName&#39;]) && $this->fromName = $config[&#39;fromName&#39;];
        !empty($config[&#39;username&#39;]) && $this->username = $config[&#39;username&#39;];
        !empty($config[&#39;password&#39;]) && $this->password = $config[&#39;password&#39;];
        if (empty($this->host) || empty($this->port) || empty($this->fromName) ||
            empty($this->username) || empty($this->password)) {
            throw new Exception(&#39;發(fā)件人信息錯(cuò)誤&#39;);
        }
    }

    public function send($address, $subject, $body)
    {
        if (empty($address) || empty($subject) || empty($body)) {
            throw new Exception(&#39;收件人信息錯(cuò)誤&#39;);
        }
        // 實(shí)例化PHPMailer核心類
        $mail = new PHPMailer();
        // 是否啟用smtp的debug進(jìn)行調(diào)試 開發(fā)環(huán)境建議開啟 生產(chǎn)環(huán)境注釋掉即可 默認(rèn)關(guān)閉debug調(diào)試模式
        $mail->SMTPDebug = 0;
        // 使用smtp鑒權(quán)方式發(fā)送郵件
        $mail->isSMTP();
        // smtp需要鑒權(quán) 這個(gè)必須是true
        $mail->SMTPAuth = true;
        // 鏈接郵箱的服務(wù)器地址
        $mail->Host = $this->host;
        // 設(shè)置使用ssl加密方式登錄鑒權(quán)
        $mail->SMTPSecure = &#39;ssl&#39;;
        // 設(shè)置ssl連接smtp服務(wù)器的遠(yuǎn)程服務(wù)器端口號(hào)
        $mail->Port = $this->port;
        // 設(shè)置發(fā)送的郵件的編碼
        $mail->CharSet = &#39;UTF-8&#39;;
        // 設(shè)置發(fā)件人昵稱 顯示在收件人郵件的發(fā)件人郵箱地址前的發(fā)件人姓名
        $mail->FromName = $this->fromName;
        // smtp登錄的賬號(hào) QQ郵箱即可
        $mail->Username = $this->username;
        // smtp登錄的密碼 使用生成的授權(quán)碼
        $mail->Password = $this->password;
        // 設(shè)置發(fā)件人郵箱地址 同登錄賬號(hào)
        $mail->From = $this->username;
        // 郵件正文是否為html編碼 注意此處是一個(gè)方法
        $mail->isHTML(true);
        // 設(shè)置收件人郵箱地址
        $mail->addAddress($address);
        // 添加多個(gè)收件人 則多次調(diào)用方法即可
        //$mail->addAddress(&#39;87654321@163.com&#39;);
        // 添加該郵件的主題
        $mail->Subject = $subject;
        // 添加郵件正文
        $mail->Body = $body;
        // 為該郵件添加附件
        //$mail->addAttachment(&#39;./example.pdf&#39;);
        // 發(fā)送郵件 返回狀態(tài)
        $status = $mail->send();
        return $status;
    }
}

注意事項(xiàng):

  1. 修改發(fā)件人信息后,只需重啟task_worker就生效,命令 kill -USER1 主進(jìn)程PID。
  2. TCP客戶端可使用swoole_client類來模擬。
  3. 短信、推送等異步任務(wù)同樣適用于此場(chǎng)景。

基于WebSocket多房間聊天功能

使用Swoole提供WebSocket服務(wù),使用Redis保存房間人員信息。

PHP主代碼:

<?php

$object = new ChatServer();

$setting = [
    &#39;log_file&#39; => &#39;swoole_ws.log&#39;,
    &#39;worker_num&#39; => 4, // 4個(gè)工作進(jìn)程
];
$ws = new swoole_websocket_server("127.0.0.1", 9502);
$ws->set($setting);

$ws->on(&#39;WorkerStart&#39;, array($object, &#39;onWorkerStart&#39;));
$ws->on(&#39;open&#39;, array($object, &#39;onOpen&#39;));
$ws->on(&#39;message&#39;, array($object, &#39;onMessage&#39;));
$ws->on(&#39;close&#39;, array($object, &#39;onClose&#39;));

$ws->start();

class ChatServer
{
    /** @var  Redis */
    private $redis;

    public function __construct()
    {
        echo "啟動(dòng)前清理數(shù)據(jù)\n";
        $redis = new Redis();
        $redis->connect(&#39;127.0.0.1&#39;, 6379);
        if ($redis->ping() != &#39;+PONG&#39;) {
            echo "redis連接失敗\n";exit;
        }
        $delKeys = $redis->keys(&#39;fd_*&#39;);
        foreach ($delKeys as $key) {
            $redis->del($key);
        }
        $delKeys = $redis->keys(&#39;roomId_*&#39;);
        foreach ($delKeys as $key) {
            $redis->del($key);
        }
    }

    public function onWorkerStart($ws, $workerId)
    {
        $redis = new Redis();
        $redis->connect(&#39;127.0.0.1&#39;, 6379);
        if ($redis->ping() != &#39;+PONG&#39;) {
            echo "redis連接失敗\n";
        }
        $this->redis = $redis;
    }

    public function onOpen($ws, $request)
    {
        echo "fd:{$request->fd} is open\n";
        if (empty($request->get[&#39;roomId&#39;]) || empty($request->get[&#39;nick&#39;])) {
            $status = &#39;fail&#39;;
        } else {
            //建立身份關(guān)聯(lián)
            $this->redis->hSet("fd_".$request->fd, &#39;roomId&#39;, $request->get[&#39;roomId&#39;]);
            $this->redis->hSet("fd_".$request->fd, &#39;nick&#39;, $request->get[&#39;nick&#39;]);
            $this->redis->sAdd("roomId_".$request->get[&#39;roomId&#39;], $request->fd);

            $status = &#39;success&#39;;
        }
        $sendData = [
            &#39;cmd&#39; => &#39;open&#39;,
            &#39;data&#39; => [
                &#39;status&#39; => $status
            ]
        ];
        $ws->push($request->fd, json_encode($sendData));
    }

    public function onMessage($ws, $frame)
    {
        echo "fd:[$frame->fd}, Message: {$frame->data}\n";
        if (!empty($frame->data)) {
            $fdInfo = $this->redis->hGetAll("fd_".$frame->fd);
            if (!empty($fdInfo[&#39;nick&#39;]) && !empty($fdInfo[&#39;roomId&#39;])) {
                $sendData = [
                    &#39;cmd&#39; => &#39;ReceiveMessage&#39;,
                    &#39;data&#39; => [
                        &#39;nick&#39; => $fdInfo[&#39;nick&#39;],
                        &#39;msg&#39; => $frame->data,
                    ]
                ];
                $fdArr = $this->redis->sMembers("roomId_".$fdInfo[&#39;roomId&#39;]);
                foreach ($fdArr as $fd) {
                    $ws->push($fd, json_encode($sendData));
                }
            }
        }
    }

    public function onClose($ws, $fd, $reactorId)
    {
        echo "fd:{$fd} is closed\n";
        //刪除fd身份數(shù)據(jù)并在房間內(nèi)移動(dòng)該fd
        $fdInfo = $this->redis->hGetAll("fd_".$fd);
        if (!empty($fdInfo[&#39;roomId&#39;])) {
            $this->redis->sRem("roomId_".$fdInfo[&#39;roomId&#39;], $fd);
        }
        $this->redis->del("fd_".$fd);
    }
}

注意事項(xiàng):

1.Worker進(jìn)程之間不能共享變量,這里使用Redis來共享數(shù)據(jù)。

2.Worker進(jìn)程不能共用同一個(gè)Redis客戶端,需要放到onWorkerStart中實(shí)例化。

3.客戶端可使用JS內(nèi)置等WebSokcet客戶端,異步的PHP程序可使用Swoole\Http\Client,同步可以使用swoole/framework提供的同步WebSocket客戶端。

基于HTTP的簡易框架

使用Swoole提供HTTP服務(wù),模擬官方Swoole框架實(shí)現(xiàn)一個(gè)簡易框架。

PHP主代碼:

<?php

$object = new AppServer();

$setting = [
    &#39;log_file&#39; => &#39;swoole_http.log&#39;,
    &#39;worker_num&#39; => 4, // 4個(gè)工作進(jìn)程
];
$server = new swoole_http_server("127.0.0.1", 9503);
$server->set($setting);

$server->on(&#39;request&#39;, array($object, &#39;onRequest&#39;));
$server->on(&#39;close&#39;, array($object, &#39;onClose&#39;));

$server->start();

/**
 * Class AppServer
 * @property \swoole_http_request $request
 * @property \swoole_http_response $response
 * @property \PDO $db
 * @property \lib\Session $session
 */
class AppServer
{
    private $module = [];

    /** @var AppServer */
    private static $instance;

    public static function getInstance()
    {
        return self::$instance;
    }

    public function __construct()
    {
        $baseControllerFile = __DIR__ .&#39;/controller/Base.php&#39;;
        require_once "$baseControllerFile";
    }

    /**
     * @param swoole_http_request $request
     * @param swoole_http_response $response
     */
    public function onRequest($request, $response)
    {
        $this->module[&#39;request&#39;] = $request;
        $this->module[&#39;response&#39;] = $response;
        self::$instance = $this;

        list($controllerName, $methodName) = $this->route($request);
        empty($controllerName) && $controllerName = &#39;index&#39;;
        empty($methodName) && $methodName = &#39;index&#39;;

        try {
            $controllerClass = "\\controller\\" . ucfirst($controllerName);
            $controllerFile = __DIR__ . "/controller/" . ucfirst($controllerName) . ".php";
            if (!class_exists($controllerClass, false)) {
                if (!is_file($controllerFile)) {
                    throw new Exception(&#39;控制器不存在&#39;);
                }
                require_once "$controllerFile";
            }

            $controller = new $controllerClass($this);
            if (!method_exists($controller, $methodName)) {
                throw new Exception(&#39;控制器方法不存在&#39;);
            }

            ob_start();
            $return = $controller->$methodName();
            $return .= ob_get_contents();
            ob_end_clean();
            $this->session->end();
            $response->end($return);
        } catch (Exception $e) {
            $response->status(500);
            $response->end($e->getMessage());
        }
    }

    private function route($request)
    {
        $pathInfo = explode(&#39;/&#39;, $request->server[&#39;path_info&#39;]);
        return [$pathInfo[1], $pathInfo[2]];
    }

    public function onClose($server, $fd, $reactorId)
    {

    }

    public function __get($name)
    {
        if (!in_array($name, array(&#39;request&#39;, &#39;response&#39;, &#39;db&#39;, &#39;session&#39;))) {
            return null;
        }
        if (empty($this->module[$name])) {
            $moduleClass = "\\lib\\" . ucfirst($name);
            $moduleFile = __DIR__ . &#39;/lib/&#39; . ucfirst($name) . ".php";
            if (is_file($moduleFile)) {
                require_once "$moduleFile";
                $object = new $moduleClass;
                $this->module[$name] = $object;
            }
        }
        return $this->module[$name];
    }
}

使用header和setCooike示例:

<?php

namespace controller;

class Http extends Base
{
    public function header()
    {
        //發(fā)送Http狀態(tài)碼,如500, 404等等
        $this->response->status(302);
        //使用此函數(shù)代替PHP的header函數(shù)
        $this->response->header(&#39;Location&#39;, &#39;http://www.baidu.com/&#39;);
    }

    public function cookie()
    {
        $this->response->cookie(&#39;http_cookie&#39;,&#39;http_cookie_value&#39;);
    }
}

Session實(shí)現(xiàn):

<?php

namespace lib;

class Session
{
    private $sessionId;
    private $cookieKey;
    private $storeDir;
    private $file;
    private $isStart;

    public function __construct()
    {
        $this->cookieKey = &#39;PHPSESSID&#39;;
        $this->storeDir = &#39;tmp/&#39;;
        $this->isStart = false;
    }

    public function start()
    {
        $this->isStart = true;
        $appServer = \AppServer::getInstance();
        $request = $appServer->request;
        $response = $appServer->response;
        $sessionId = $request->cookie[$this->cookieKey];
        if (empty($sessionId)){
            $sessionId = uniqid();
            $response->cookie($this->cookieKey, $sessionId);
        }
        $this->sessionId = $sessionId;
        $storeFile = $this->storeDir . $sessionId;
        if (!is_file($storeFile)) {
            touch($storeFile);
        }
        $session = $this->get($storeFile);
        $_SESSION = $session;
    }

    public function end()
    {
        $this->save();
    }

    public function commit()
    {
        $this->save();
    }

    private function save()
    {
        if ($this->isStart) {
            $data = json_encode($_SESSION);
            ftruncate($this->file, 0);

            if ($data) {
                rewind($this->file);
                fwrite($this->file, $data);
            }
            flock($this->file, LOCK_UN);
            fclose($this->file);
        }
    }

    private function get($fileName)
    {
        $this->file = fopen($fileName, &#39;c+b&#39;);
        if(flock($this->file, LOCK_EX | LOCK_NB)) {
            $data = [];
            clearstatcache();
            if (filesize($fileName) > 0) {
                $data = fread($this->file, filesize($fileName));
                $data = json_decode($data, true);
            }
            return $data;
        }
    }
}

注意事項(xiàng):

  1. 使用Redis/MySQL等客戶端理應(yīng)使用線程池,參照官方Swoole框架。
  2. Swoole是在執(zhí)行PHP文件這一階段進(jìn)行接管,因此header,setCooike,seesion_start不可用,header和setCooike可用$response變量實(shí)現(xiàn),Session可自行實(shí)現(xiàn)。
  3. 推薦查看官方框架:Swoole框架。

上述demo可以戳這里:demo

總結(jié)

Swoole的應(yīng)用遠(yuǎn)不如此,Swoole就像打開了PHP世界的新大門,我覺得每一位PHPer都應(yīng)該學(xué)習(xí)和掌握Swoole的用法,能學(xué)到很多使用LAMP/LNMP模式時(shí)未涉及到的知識(shí)點(diǎn)。

The above is the detailed content of Introducing a simple implementation example of Swoole. For more information, please follow other related articles on the PHP Chinese website!

Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn

Hot AI Tools

Undress AI Tool

Undress AI Tool

Undress images for free

Undresser.AI Undress

Undresser.AI Undress

AI-powered app for creating realistic nude photos

AI Clothes Remover

AI Clothes Remover

Online AI tool for removing clothes from photos.

Clothoff.io

Clothoff.io

AI clothes remover

Video Face Swap

Video Face Swap

Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Tools

Notepad++7.3.1

Notepad++7.3.1

Easy-to-use and free code editor

SublimeText3 Chinese version

SublimeText3 Chinese version

Chinese version, very easy to use

Zend Studio 13.0.1

Zend Studio 13.0.1

Powerful PHP integrated development environment

Dreamweaver CS6

Dreamweaver CS6

Visual web development tools

SublimeText3 Mac version

SublimeText3 Mac version

God-level code editing software (SublimeText3)

Hot Topics

PHP Tutorial
1488
72
How to use swoole coroutine in laravel How to use swoole coroutine in laravel Apr 09, 2024 pm 06:48 PM

Using Swoole coroutines in Laravel can process a large number of requests concurrently. The advantages include: Concurrent processing: allows multiple requests to be processed at the same time. High performance: Based on the Linux epoll event mechanism, it processes requests efficiently. Low resource consumption: requires fewer server resources. Easy to integrate: Seamless integration with Laravel framework, simple to use.

How to use Swoole to implement a high-performance HTTP reverse proxy server How to use Swoole to implement a high-performance HTTP reverse proxy server Nov 07, 2023 am 08:18 AM

How to use Swoole to implement a high-performance HTTP reverse proxy server Swoole is a high-performance, asynchronous, and concurrent network communication framework based on the PHP language. It provides a series of network functions and can be used to implement HTTP servers, WebSocket servers, etc. In this article, we will introduce how to use Swoole to implement a high-performance HTTP reverse proxy server and provide specific code examples. Environment configuration First, we need to install the Swoole extension on the server

Which one is better, swoole or workerman? Which one is better, swoole or workerman? Apr 09, 2024 pm 07:00 PM

Swoole and Workerman are both high-performance PHP server frameworks. Known for its asynchronous processing, excellent performance, and scalability, Swoole is suitable for projects that need to handle a large number of concurrent requests and high throughput. Workerman offers the flexibility of both asynchronous and synchronous modes, with an intuitive API that is better suited for ease of use and projects that handle lower concurrency volumes.

Which one has better performance, swoole or java? Which one has better performance, swoole or java? Apr 09, 2024 pm 07:03 PM

Performance comparison: Throughput: Swoole has higher throughput thanks to its coroutine mechanism. Latency: Swoole's coroutine context switching has lower overhead and smaller latency. Memory consumption: Swoole's coroutines occupy less memory. Ease of use: Swoole provides an easier-to-use concurrent programming API.

How to restart the service in swoole framework How to restart the service in swoole framework Apr 09, 2024 pm 06:15 PM

To restart the Swoole service, follow these steps: Check the service status and get the PID. Use "kill -15 PID" to stop the service. Restart the service using the same command that was used to start the service.

Swoole in action: How to use coroutines for concurrent task processing Swoole in action: How to use coroutines for concurrent task processing Nov 07, 2023 pm 02:55 PM

Swoole in action: How to use coroutines for concurrent task processing Introduction In daily development, we often encounter situations where we need to handle multiple tasks at the same time. The traditional processing method is to use multi-threads or multi-processes to achieve concurrent processing, but this method has certain problems in performance and resource consumption. As a scripting language, PHP usually cannot directly use multi-threading or multi-process methods to handle tasks. However, with the help of the Swoole coroutine library, we can use coroutines to achieve high-performance concurrent task processing. This article will introduce

How does swoole_process allow users to switch? How does swoole_process allow users to switch? Apr 09, 2024 pm 06:21 PM

Swoole Process allows users to switch. The specific steps are: create a process; set the process user; start the process.

How to use Swoole to implement WebSocket communication How to use Swoole to implement WebSocket communication Nov 07, 2023 pm 12:56 PM

Swoole is a high-performance PHP coroutine network framework that supports asynchronous IO, multi-process, multi-threading, coroutine and other features. Among them, the WebSocket component provided by Swoole can be used to achieve real-time two-way communication and is an ideal choice for building real-time applications. This article will introduce how to use Swoole to implement WebSocket communication and provide specific code examples. 1. Environment preparation Before using Swoole to implement WebSocket communication, you need to ensure that the Swoole extension has been installed. passable

See all articles