热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Swoole实践:2使用Swoole发送邮件[php入门]

Swoole可以执行异步操作,因此在web页面将请求提交给Swoole处理后,不用等待返回结果,页面也不会卡顿。Swoole在后台将耗时长的操作进行异步处理,从而改善用户体验,例如

Swoole实践:2-使用Swoole发送邮件[linux入门]

Swoole可以执行异步操作,因此在web页面将请求提交给Swoole处理后,不用等待返回结果,页面也不会卡顿。Swoole在后台将耗时长的操作进行异步处理,从而改善用户体验,例如本节要给大家讲解的Swoole处理邮件。

准备

请按照上一节:Swoole实践:1-使用Composer构建项目,构建好项目。并使用composer安装邮件发送组件:phpmailer。

composer require phpmailer/phpmailer

主程序

在目录:src/App/下建立Mail.php,用作Swoole服务端主程序。

 
namespace HellowebaSwoole;

use swoole_server;
use PHPMailerPHPMailerPHPMailer;
use PHPMailerPHPMailerException;

class Mail
{
    protected $serv;
    protected $host = "127.0.0.1";
    protected $port = 9502;
    // 进程名称
    protected $taskName = "swooleMailer";
    // PID路径
    protected $pidPath = "/run/swooleMail.pid";
    // 设置运行时参数
    protected $optiOns= [
        "worker_num" => 4, //worker进程数,一般设置为CPU数的1-4倍  
        "daemonize" => true, //启用守护进程
        "log_file" => "/data/logs/swoole.log", //指定swoole错误日志文件
        "log_level" => 0, //日志级别 范围是0-5,0-DEBUG,1-TRACE,2-INFO,3-NOTICE,4-WARNING,5-ERROR
        "dispatch_mode" => 1, //数据包分发策略,1-轮询模式
        "task_worker_num" => 4, //task进程的数量
        "task_ipc_mode" => 3, //使用消息队列通信,并设置为争抢模式
        //"heartbeat_idle_time" => 600, //一个连接如果600秒内未向服务器发送任何数据,此连接将被强制关闭
        //"heartbeat_check_interval" => 60, //启用心跳检测,每隔60s轮循一次
    ];
    // 邮件服务器配置
    protected $mailCOnfig= [
        "smtp_server" => "smtp.163.com",
        "username" => "example@163.com",
        "password" => "",// SMTP 密码/口令
        "secure" => "ssl", //Enable TLS encryption, `ssl` also accepted
        "port" => 465, // tcp邮件服务器端口
    ];
    // 安全密钥
    protected $safeKey = "MYgGnQE33ytd2jDFADS39DSEWsdD24sK";


    public function __construct($mailConfig, $optiOns= [])
    {
        // 构建Server对象,监听端口
        $this->serv = new swoole_server($this->host, $this->port);

        if (!empty($options)) {
            $this->optiOns= array_merge($this->options, $options);
        }
        $this->serv->set($this->options);

        $this->mailCOnfig= $mailConfig;

        // 注册事件
        $this->serv->on("Start", [$this, "onStart"]);
        $this->serv->on("Connect", [$this, "onConnect"]);
        $this->serv->on("Receive", [$this, "onReceive"]);
        $this->serv->on("Task", [$this, "onTask"]);  
        $this->serv->on("Finish", [$this, "onFinish"]);
        $this->serv->on("Close", [$this, "onClose"]);

        // 启动服务
        //$this->serv->start();
    }

    protected function init()
    {
        //
    }

    public function start()
    {
        // Run worker
        $this->serv->start();
    }

    public function onStart($serv)
    {
        // 设置进程名
        cli_set_process_title($this->taskName);
        //记录进程id,脚本实现自动重启
        $pid = "{$serv->master_pid}
{$serv->manager_pid}";
        file_put_contents($this->pidPath, $pid);
    }

    //监听连接进入事件
    public function onConnect($serv, $fd, $from_id)
    {
        $serv->send($fd, "Hello {$fd}!" );
    }

    // 监听数据接收事件
    public function onReceive(swoole_server $serv, $fd, $from_id, $data)
    {
        $res["result"] = "failed";
        $key = $this->safeKey;

        $req = json_decode($data, true);
        $action = $req["action"];
        $token = $req["token"];
        $timestamp = $req["timestamp"];

        if (time() - $timestamp > 180) {
            $res["code"] = "已超时";
            $serv->send($fd, json_encode($res));
            exit;
        }

        $token_get = md5($action.$timestamp.$key);
        if ($token != $token_get) {
            $res["msg"] = "非法提交";
            $serv->send($fd, json_encode($res));
            exit;
        }

        $res["result"] = "success";
        $serv->send($fd, json_encode($res)); // 同步返回消息给客户端
        $serv->task($data);  // 执行异步任务

    }

    /**
    * @param $serv swoole_server swoole_server对象
    * @param $task_id int 任务id
    * @param $from_id int 投递任务的worker_id
    * @param $data string 投递的数据
    */
    public function onTask(swoole_server $serv, $task_id, $from_id, $data)
    {
        $res["result"] = "failed";
        $req = json_decode($data, true);
        $action = $req["action"];
        echo date("Y-m-d H:i:s")." onTask: [".$action."].
";
        switch ($action) {
            case "sendMail": //发送单个邮件
                $mailData = [
                    "emailAddress" => "abc@example.com", //接收方,改成自己的邮箱可以测试接收邮件
                    "subject" => "swoole实验室",
                    "body" => "测试This is the HTML message body in bold!,
欢迎访问www.helloweba.net"
, "attach" => "/home/swoole/public/a.jpg" ]; $this->sendMail($mailData); break; default: break; } } /** * @param $serv swoole_server swoole_server对象 * @param $task_id int 任务id * @param $data string 任务返回的数据 */ public function onFinish(swoole_server $serv, $task_id, $data) { // } // 监听连接关闭事件 public function onClose($serv, $fd, $from_id) { echo "Client {$fd} close connection "; } public function stop() { $this->serv->stop(); } private function sendMail($mail_data = []) { $mail = new PHPMailer(true); try { $mailCOnfig= $this->mailConfig; //$mail->SMTPDebug = 2; // 启用Debug $mail->isSMTP(); // Set mailer to use SMTP $mail->Host = $mailConfig["smtp_server"]; // SMTP服务 $mail->SMTPAuth = true; // Enable SMTP authentication $mail->Username = $mailConfig["username"]; // SMTP 用户名 $mail->Password = $mailConfig["password"]; // SMTP 密码/口令 $mail->SMTPSecure = $mailConfig["secure"]; // Enable TLS encryption, `ssl` also accepted $mail->Port = $mailConfig["port"]; // TCP 端口 $mail->CharSet = "UTF-8"; //字符集 $mail->Encoding = "base64"; //编码方式 //Recipients $mail->setFrom($mailConfig["username"], "Helloweba"); //发件人地址,名称 $mail->addAddress($mail_data["emailAddress"], "亲"); // 收件人地址和名称 //$mail->addCC("hellowebanet@163.com"); // 抄送 //Attachments if (isset($mail_data["attach"])) { $mail->addAttachment($mail_data["attach"]); // 添加附件 } //$mail->addAttachment("/tmp/image.jpg", "new.jpg"); // Optional name //Content $mail->isHTML(true); // Set email format to HTML $mail->Subject = $mail_data["subject"]; $mail->Body = $mail_data["body"]; $mail->send(); return true; } catch (Exception $e) { echo "Message could not be sent. Mailer Error: ". $mail->ErrorInfo; return false; } } }

Swoole启动后,服务端会监听数据接收事件onReceive(),当接收到客户端发来的数据时会进行相应的处理。我们在这里对源数据进行验证,然后作为任务投递给onTask()sendMail()是使用phpmailler来发送邮件的,这里可以参考使用PHPMailer发送带附件并支持HTML内容的邮件。

运行服务端

在public/目录下建立mailServer.php,代码如下:

 
require dirname(__DIR__) . "/vendor/autoload.php";

use HellowebaSwooleMail;

$cOnfig= [
    "smtp_server" => "smtp.163.com", //邮件服务器
    "username" => "xxxxx@163.com", //这里是用作发送方的邮箱号
    "password" => "xxxxx",// SMTP 密码/口令
    "secure" => "ssl", //Enable TLS encryption, `ssl` also accepted
    "port" => 465, // tcp邮件服务器端口
];
$server = new Mail($config);
$server->start();

你可以注册一个163邮箱,然后开通smtp功能。我DEMO中使用的是163邮箱发邮件发多了被封号了,所以在线演示demo没上传了。配置好邮件服务器参数后,运行:

php mailServer.php

此时再使用命令netstat -lntp查看进程:

swoole-1.jpg

当你看到已经在监听9502端口时,我们的swoole邮件服务端就已经启动好了。

运行客户端

在public/目录下新建mailClient.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", 9502 , 1) ) {
            echo "Error: {$this->client->errMsg}[{$this->client->errCode}]
";
        }
        
        $action = "sendMail";
        $time = time();
        $key = "MYgGnQE33ytd2jDFADS39DSEWsdD24sK";
        $token = md5($action.$time.$key);
        $data = [
            "action" => $action,
            "token" => $token,
            "timestamp" => $time
        ];
        $msg = json_encode($data);

        $this->client->send( $msg );
        $message = $this->client->recv();
        echo "Get Message From Server:{$message}
";
    }
}

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

运行命令启动客户端:

php mailClient.php

此时在命令行窗口会返回如下信息:

[root@localhost public]# php mailClient.php 
Get Message From Server:{"result":"success"}

这样就已经执行邮件发送任务了,如果出现故障,可以查看日志文件/data/logs/swoole.log。

小结

本节是一个简单的单一邮件发送例子。由Swoole客户端提交发送邮件的指令到Swoole服务端,服务端接收到需要发送邮件的指令后,调用邮件发送服务来发邮件的。由于发送邮件可能比较耗时,不同的邮件服务器发送耗时也不一样,经测试单个邮件发送一般在1秒内完成,这个如果在web页面上发送是可以接受的,但是使用Swoole来发送的话我们提交发送指令就不用管结果了,Swoole在后台自己进行发送邮件。如果是大批量发送大量邮件时,我们可以使用Swoole+队列的方案,下节我们来测试批量队列发送邮件,敬请关注。


推荐阅读
  • 本文介绍了Python高级网络编程及TCP/IP协议簇的OSI七层模型。首先简单介绍了七层模型的各层及其封装解封装过程。然后讨论了程序开发中涉及到的网络通信内容,主要包括TCP协议、UDP协议和IPV4协议。最后还介绍了socket编程、聊天socket实现、远程执行命令、上传文件、socketserver及其源码分析等相关内容。 ... [详细]
  • 本文介绍了Oracle数据库中tnsnames.ora文件的作用和配置方法。tnsnames.ora文件在数据库启动过程中会被读取,用于解析LOCAL_LISTENER,并且与侦听无关。文章还提供了配置LOCAL_LISTENER和1522端口的示例,并展示了listener.ora文件的内容。 ... [详细]
  • 本文讨论了在openwrt-17.01版本中,mt7628设备上初始化启动时eth0的mac地址总是随机生成的问题。每次随机生成的eth0的mac地址都会写到/sys/class/net/eth0/address目录下,而openwrt-17.01原版的SDK会根据随机生成的eth0的mac地址再生成eth0.1、eth0.2等,生成后的mac地址会保存在/etc/config/network下。 ... [详细]
  • iOS超签签名服务器搭建及其优劣势
    本文介绍了搭建iOS超签签名服务器的原因和优势,包括不掉签、用户可以直接安装不需要信任、体验好等。同时也提到了超签的劣势,即一个证书只能安装100个,成本较高。文章还详细介绍了超签的实现原理,包括用户请求服务器安装mobileconfig文件、服务器调用苹果接口添加udid等步骤。最后,还提到了生成mobileconfig文件和导出AppleWorldwideDeveloperRelationsCertificationAuthority证书的方法。 ... [详细]
  • 重入锁(ReentrantLock)学习及实现原理
    本文介绍了重入锁(ReentrantLock)的学习及实现原理。在学习synchronized的基础上,重入锁提供了更多的灵活性和功能。文章详细介绍了重入锁的特性、使用方法和实现原理,并提供了类图和测试代码供读者参考。重入锁支持重入和公平与非公平两种实现方式,通过对比和分析,读者可以更好地理解和应用重入锁。 ... [详细]
  • Nginx使用AWStats日志分析的步骤及注意事项
    本文介绍了在Centos7操作系统上使用Nginx和AWStats进行日志分析的步骤和注意事项。通过AWStats可以统计网站的访问量、IP地址、操作系统、浏览器等信息,并提供精确到每月、每日、每小时的数据。在部署AWStats之前需要确认服务器上已经安装了Perl环境,并进行DNS解析。 ... [详细]
  • 基于PgpoolII的PostgreSQL集群安装与配置教程
    本文介绍了基于PgpoolII的PostgreSQL集群的安装与配置教程。Pgpool-II是一个位于PostgreSQL服务器和PostgreSQL数据库客户端之间的中间件,提供了连接池、复制、负载均衡、缓存、看门狗、限制链接等功能,可以用于搭建高可用的PostgreSQL集群。文章详细介绍了通过yum安装Pgpool-II的步骤,并提供了相关的官方参考地址。 ... [详细]
  • http:my.oschina.netleejun2005blog136820刚看到群里又有同学在说HTTP协议下的Get请求参数长度是有大小限制的,最大不能超过XX ... [详细]
  • 本文介绍了在Linux下安装和配置Kafka的方法,包括安装JDK、下载和解压Kafka、配置Kafka的参数,以及配置Kafka的日志目录、服务器IP和日志存放路径等。同时还提供了单机配置部署的方法和zookeeper地址和端口的配置。通过实操成功的案例,帮助读者快速完成Kafka的安装和配置。 ... [详细]
  • Ihavethefollowingonhtml我在html上有以下内容<html><head><scriptsrc..3003_Tes ... [详细]
  • 本文介绍了在CentOS上安装Python2.7.2的详细步骤,包括下载、解压、编译和安装等操作。同时提供了一些注意事项,以及测试安装是否成功的方法。 ... [详细]
  • 本文介绍了操作系统的定义和功能,包括操作系统的本质、用户界面以及系统调用的分类。同时还介绍了进程和线程的区别,包括进程和线程的定义和作用。 ... [详细]
  • 深入解析Linux下的I/O多路转接epoll技术
    本文深入解析了Linux下的I/O多路转接epoll技术,介绍了select和poll函数的问题,以及epoll函数的设计和优点。同时讲解了epoll函数的使用方法,包括epoll_create和epoll_ctl两个系统调用。 ... [详细]
  • 本文介绍了解决java开源项目apache commons email简单使用报错的方法,包括使用正确的JAR包和正确的代码配置,以及相关参数的设置。详细介绍了如何使用apache commons email发送邮件。 ... [详细]
  • POCOCLibraies属于功能广泛、轻量级别的开源框架库,它拥有媲美Boost库的功能以及较小的体积广泛应用在物联网平台、工业自动化等领域。POCOCLibrai ... [详细]
author-avatar
君字翔宇_323
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有