最近做公司的一个管理系统,需要把每天的统计信息发送到领导的邮箱。由于使用SMTP
协议发送邮件的速度太慢,所以只能异步发送。刚开始实现了一个基于php-reque
redis
的异步发送,但后来我觉得实现得不够优雅,可控性也不是很高,所以后面选择了使用swoole
扩展来实现异步。
Swoole
简介极安装请参见文档:http://www.swoole.com/
swoole
的模式大致是,写一个server
端,通过cli
模式运行,实现守护进程。然后在通过一个client
端去连接server
端,并发送信息,server端收到信息后,通过回调函数,执行相应的程序。
使用server
响应请求并发送邮件:
发送邮件使用了swiftmailer
,可以通过composer
安装它:php composer.phar require swiftmailer/swiftmailer @stable
。
<?php
/**
* @author fatrbaby
* @created 2015/4/29 9:10
*/
require __DIR__ . '/vendor/autoload.php';
class MailServer
{
const MAIL_USERNAME = 'user@example.com';
const MAIL_PASSWORD = 'your-password';
private $logger = null;
private $server = null;
public function __construct()
{
$this->server = new swoole_server('127.0.0.1', 9501);
$this->server->set([
'worker_num' => 8,
'daemonize' => false,
'max_request' => 10000,
'dispatch_mode' => 2,
'debug_mode'=> 1,
]);
$this->server->on('Start', [$this, 'onStart']);
$this->server->on('Connect', [$this, 'onConnect']);
$this->server->on('Receive', [$this, 'onReceive']);
$this->server->on('Close', [$this, 'onClose']);
$this->server->start();
}
public function onStart()
{
}
public function onConnect($server, $descriptors, $fromId)
{
}
public function onReceive(swoole_server $server, $descriptors, $fromId, $data)
{
$msg = json_decode($data, true);
$sent = $this->sendMail($msg['address'], $msg['subject'], $msg['body']);
printf("%s mail is sent.n", $sent);
}
public function onClose($server, $descriptors, $fromId)
{
}
public function sendMail($address, $subject, $body)
{
$body = htmlspecialchars_decode($body);
$transport = Swift_SmtpTransport::newInstance('smtp.partner.outlook.cn', 587, 'tls');
$transport->setUsername(self::MAIL_USERNAME);
$transport->setPassword(self::MAIL_PASSWORD);
$mailer = Swift_Mailer::newInstance($transport);
$message = Swift_Message::newInstance();
$message->setFrom([self::MAIL_USERNAME=>'××管理系统']);
$message->setTo($address);
$message->setSubject($subject);
$message->addPart($body, 'text/html');
$message->setBody($body);
return $mailer->send($message);
}
}
$server = new MailServer();
使用cli
启动服务端:php mail_server.php
, 如果想服务端后台执行,修改配置数组'daemonize' => false
为'daemonize' => true
。
使用client
连接server
并发送数据:
<?php
/**
* @author fatrbaby
* @created 2015/4/29 9:20
*/
class MailClient
{
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)) {
throw new CException(sprintf('Swoole Error: %s', $this->client->errCode));
}
}
public function send($data)
{
if ($this->client->isConnected()) {
if (!is_string($data)) {
$data = json_encode($data);
}
return $this->client->send($data);
} else {
throw new CException('Swoole Server does not connected.');
}
}
public function close()
{
$this->client->close();
}
}
使用:
代码语言:javascript复制$data = array(
'address' => $mails,
'subject' => $subject,
'body' => htmlspecialchars($body),
);
$mailClient = new MailClient();
$mailClient->connect();
if ($mailClient->send($data)) {
echo 'success';
} else {
echo 'fail';
}
$mailClient->close();