網上查閱資料有現成和workerman結合的composer組件,但我的感受不太靠譜,github上star太少,並且怕有問題也很差調,就想本身先試試。php
個人辦法由於修改要一點Workerman源碼,且是直接引入Workerman的代碼文件,感受有點low,但才智有限,暫時沒想到更好的方法。laravel
準備:git
1.需先了解Laravel框架下命令行的使用,參考中文版教程github
2.需瞭解Workerman的基本知識json
場景:用戶註冊後,異步方式給用戶發送郵件提醒app
php artisan make:command SendEmail
namespace App\Console\Commands; use Illuminate\Console\Command; use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Mail; use Illuminate\Mail\Message; use Workerman\Worker; require app_path('Workerman/Workerman_Linux/Autoloader.php'); class SendEmail extends Command { /** * The name and signature of the console command. * * @var string */ protected $signature = 'send:email {action}'; /** * The console command description. * * @var string */ protected $description = 'Command description'; /** * Create a new command instance. * * @return void */ public function __construct() { parent::__construct(); } /** * Execute the console command. * */ public function handle() { $mailWorker = new Worker('Text://0.0.0.0:12345'); $mailWorker->count = 4; $mailWorker->name = 'MailWorker'; $mailWorker->onMessage = function ($connection, $emailData) { $emailData = json_decode($emailData); $name = $emailData->name; $email = $emailData->to; Mail::raw('註冊成功', function (Message $message) use ($email) { $message->to($email)->subject(trans('mail.welcome_register')); }); // 寫入日誌 Log::useFiles(storage_path() . '/logs/event.log', 'info'); Log::info("{$name}({$email})註冊成功"); }; Worker::runAll(); } }
以上是workerman服務端,用命令行啓動:composer
php artisan send:email start
此時命令行下會報錯:Workerman[artisan] not run,緣由是Workerman會把第一個參數artisan當前啓動文件,而實際上,send:email纔是咱們想要的啓動文件框架
解決:修改Workerman的解析參數代碼異步
Workerman\Workerman_Linux\Worker.php,修改parseCommand方法(只要把$argv的鍵都加1就行):socket
/** * Parse command. * php yourfile.php start | stop | restart | reload | status * * @return void */ protected static function parseCommand() { global $argv; if($argv[0] == 'artisan') // laravel框架下處理 { // Check argv; $start_file = $argv[1]; if (!isset($argv[2])) { exit("Usage: php yourfile.php {start|stop|restart|reload|status}\n"); } // Get command. $command = trim($argv[2]); $command2 = isset($argv[3]) ? $argv[3] : ''; } else { // Check argv; $start_file = $argv[0]; if (!isset($argv[1])) { exit("Usage: php yourfile.php {start|stop|restart|reload|status}\n"); } // Get command. $command = trim($argv[1]); $command2 = isset($argv[2]) ? $argv[2] : ''; } // 只要略修改上面的參數解析部分便可 .......................... }
從新啓動OK:
php artisan send:email start
個人郵件操做代碼是看成事件邏輯,因此在事件監聽器文件寫代碼:
app\Listeners\SendMailEventListener.php:
<?php namespace App\Listeners; use App\Events\SendMailEvent;class SendMailEventListener extends BaseEventListener { /** * Create the event listener. * * @return void */ public function __construct() { // } /** * Handle the event. * * @param SendMailEvent $event * @return void */ public function handle($event) { // 發送郵件通知註冊成功 if ($event->user->scene == 'do_register') { $email = $event->user->email; //$ip = "mail_worker 的ip" ,本機的話爲127.0.0.1 $socket = @stream_socket_client('tcp://127.0.0.1:12345', $errno, $errmsg, 5); if ($socket) { $mail_data = ['name'=>$event->user->name,'to' => $email, 'content' => trans('mail.welcome_register')]; // 注意,Text協議後面"\n"換行符是必須的 $mail_buffer = json_encode($mail_data) . "\n"; // 發送給mail worker fwrite($socket, $mail_buffer); } // $email = $event->user->email; // Mail::raw('註冊成功',function (Message $message) use ($email) { // $message->to($email)->subject(trans('mail.welcome_register')); // }); } } }
啓動服務端---註冊用戶---觸發SendEmail事件---socket客戶端往服務端寫數據---服務端發送郵件
若是各位有更好的結合方式,一塊兒交流下哈。