凉山网站开发,做图素材网站开通会员哪个好,网站开发就业前景分析,wordpress缩略图调用Swoole简单入门示例
Swoole可以让PHP 开发人员可以编写高性能的异步并发 TCP、UDP、Unix Socket、HTTP#xff0c;WebSocket 服务。Swoole 可以广泛应用于互联网、移动通信、企业软件、云计算、网络游戏、物联网(IOT)、车联网、智能家居等领域。
前提
使用Composer构建项目…Swoole简单入门示例
Swoole可以让PHP 开发人员可以编写高性能的异步并发 TCP、UDP、Unix Socket、HTTPWebSocket 服务。Swoole 可以广泛应用于互联网、移动通信、企业软件、云计算、网络游戏、物联网(IOT)、车联网、智能家居等领域。
前提
使用Composer构建项目构建好项目。
或者利用搜索引擎。
本篇介绍以下几个示例
一、使用Swoole发送邮件
二、使用Swoole实现在线聊天
三、使用Systemctl管理Swoole服务
四、使用Swoole实现毫秒级定时任务
五、使用Websocket上传文件
使用composer安装邮件发送组件phpmailer
composer require phpmailer/phpmailer
Copy
主程序
在目录src/app/下建立Mail.php用作Swoole服务端主程序。 namespace Shanhubei\Swoole;use swoole_server;
use Redis;
use PHPMailer\PHPMailer\PHPMailer;
use PHPMailer\PHPMailer\Exception;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-50-DEBUG1-TRACE2-INFO3-NOTICE4-WARNING5-ERRORdispatch_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 username163.com,password 密码/口令,// SMTP 密码/口令secure ssl, //Enable TLS encryption, ssl also acceptedport 465, // tcp邮件服务器端口];// 安全密钥protected $safeKey MDDGnQE33ytd2jDFADS39DSEWsdD24sK;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}\n{$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.].\n;switch ($action) {case sendMail: //发送单个邮件$mailData [emailAddress 2823175272qq.com,subject swoole demo,body 测试This is the HTML message body bin bold!/b,br/欢迎访问a hrefhttp://www.shanhubei.com/www.shanhubei.com/a];$this-sendMail($mailData);break;case sendMailQueue: // 批量队列发送邮件$this-sendMailQueue();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\n;}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], Shanhubei); //发件人地址名称$mail-addAddress($mail_data[emailAddress], 亲); // 收件人地址和名称//$mail-addCC(hellowebanet163.com); // 抄送//Attachmentsif (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-AltBody 这是在不支持HTML邮件客户端的纯文本格式;$mail-send();return true;} catch (\Exception $e) {echo Message could not be sent. Mailer Error: . $mail-ErrorInfo;return false;}}// 邮件发送队列private function sendMailQueue(){$redis new Redis();$redis-connect(127.0.0.1, 6379);//$password 123;//$redis-auth($password);swoole_timer_tick(1000, function($timer) use ($redis) { // 启用定时器每1秒执行一次$value $redis-lpop(mailerlist);if($value){//echo 获取redis数据: . $value;$json json_decode($value, true);$start microtime(true);$rs $this-sendMail($json);$end microtime(true);if ($rs) {echo 发送成功.$value., 耗时:. round($end - $start, 3).秒.PHP_EOL;} else { // 把发送失败的加入到失败队列中人工处理$redis-rpush(mailerlist_err, $value);}}else{swoole_timer_clear($timer); // 停止定时器echo Emaillist出队完成;}});}}
Copy
运行服务端
在public/目录下建立mailServer.php代码如下 require dirname(__DIR__) . /vendor/autoload.php;use Shanhubei\Swoole\Mail;$config [smtp_server smtp.163.com,username xxxxx163.com,password xxxx,// SMTP 密码/口令secure ssl, //Enable TLS encryption, ssl also acceptedport 465, // tcp邮件服务器端口
];
$server new Mail($config);
$server-start();
Copy
你可以注册一个163邮箱然后开通smtp功能。我DEMO中使用的是163邮箱发邮件发多了被封号了所以在线演示demo没上传了。配置好邮件服务器参数后运行
php mailServer.php
Copy
此时再使用命令netstat -lntp查看进程。
运行客户端
在public/目录下新建mailClient.php代码如下
class Client
{private $client;public function __construct() {$this-client new swoole_client(SWOOLE_SOCK_TCP);}public function connect($type) {if( !$this-client-connect(127.0.0.1, 9502 , 1) ) {echo Error: {$this-client-errMsg}[{$this-client-errCode}]\n;}// fwrite(STDOUT, 请输入消息 Please input msg);// $msg trim(fgets(STDIN));$action sendMail;if($type q){$action sendMailQueue;}$time time();$key MDDGnQE33ytd2jDFADS39DSEWsdD24sK;$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}\n;}
}$type q; //区分批量和单个发送标志if($type q){$redis new \Redis();$redis-connect(127.0.0.1, 6379);//$password 123456x;///$redis-auth($password);$arr [];$arr[0] [subject 注册cloudfog-HA,emailAddress 2823175272qq.com,body 您好您的CloudFog使用的用户名是123, 密码是123。br/请不要将此邮件泄漏给他人并尽快登录CloudFog更换新密码。如有疑问请联系管理员。];$arr[1] [subject 注册cloudfog2,emailAddress 2823175272qq.com,body a hrefhttps://www.shanhubei.com target_blank网易邮箱/a];foreach ($arr as $k$v) {$redis-rpush(mailerlist, json_encode($v, JSON_UNESCAPED_UNICODE));}
}$client new Client();
$client-connect($type);
Copy
运行命令启动客户端
php mailClient.php
Copy
此时在命令行窗口会返回如下信息
[rootlocalhost public]# php mailClient.php
Get Message From Server:{result:success}
Copy
这样就已经执行邮件发送任务了如果出现故障可以查看日志文件/data/logs/swoole.log。
然后你可以去查看对方邮箱是否收到相关邮件。
本文中使用了redis作为简单队列你也可以使用复杂点的队列rabbitmq。你也可以使用Crontab来做定时任务不过它最小粒度是分钟级别的。当然对于批量发送邮件如果你不用php的话可以用Python或者Java它们都有相当成熟的解决方案。
二、使用Swoole实现在线聊天
建立服务端主程序
准备工作就绪后我们开始来撸代码。
首先在项目目录src/app/ 下建立Chat.php用作Swoole服务端主程序。
Chat.php文件的主体结构是这样的 namespace Shanhubei\Swoole;
use swoole_websocket_server;
class Chat
{protected $ws;protected $host 0.0.0.0;protected $port 9504;// 进程名称protected $taskName swooleChat;// PID路径protected $pidFile /run/swooleChat.pid;// 设置运行时参数protected $options [worker_num 4, //worker进程数,一般设置为CPU数的1-4倍 daemonize true, //启用守护进程log_file /data/logs/chatswoole.log, //指定swoole错误日志文件log_level 3, //日志级别 范围是0-50-DEBUG1-TRACE2-INFO3-NOTICE4-WARNING5-ERRORdispatch_mode 1, //数据包分发策略,1-轮询模式];public function __construct($options []){$this-ws new swoole_websocket_server($this-host, $this-port);if (!empty($options)) {$this-options array_merge($this-options, $options);}$this-ws-set($this-options);$this-ws-on(open, [$this, onOpen]);$this-ws-on(message, [$this, onMessage]);$this-ws-on(close, [$this, onClose]);}public function start(){// Run worker$this-ws-start();}public function onOpen(swoole_websocket_server $ws, $request){// 设置进程名cli_set_process_title($this-taskName);//记录进程id,脚本实现自动重启$pid {$ws-master_pid}\n{$ws-manager_pid};file_put_contents($this-pidFile, $pid);echo server: handshake success with fd{$request-fd}\n;}public function onMessage(swoole_websocket_server $ws, $frame){//$ws-push($frame-fd, server-push:.date(Y-m-d H:i:s));$connets $ws-connections;echo count($connets).\n;echo $frame-data. \n;if ($frame-data 美女) {$mmpic [http://pic15.photophoto.cn/20100402/0036036889148227_b.jpg,http://pic23.nipic.com/20120814/5914324_155903179106_2.jpg,http://pic40.nipic.com/20140403/8614226_162017444195_2.jpg];$picKey array_rand($mmpic);$ws-push($frame-fd, file_get_contents($mmpic[$picKey]), WEBSOCKET_OPCODE_BINARY);} else {$ws-push($frame-fd, $this-reply($frame-data));}}public function onClose($ws, $fid){echo client {$fid} closed\n;foreach ($ws-connections as $fd) {$ws-push($fd, $fid. 已离开);}}private function reply($str) {$str mb_strtolower($str);switch ($str) {case hello:$res Hello, Friend.;break;case fuck:$res Fuck bitch.;break;case ping:$res PONG.;break;case time:$res date(H:i:s);break;default:$res $str;break;}return $res;}
}
Copy
我们需要往onMessage()方法里填代码。在这里服务端接收客户端消息并作出相应动作。Websocket可以向客户端发送字符串、二进制等形式消息。
public function onMessage(swoole_websocket_server $ws, $frame){//$ws-push($frame-fd, server-push:.date(Y-m-d H:i:s));if ($frame-data 美女) {$mmpic [http://pic15.photophoto.cn/20100402/0036036889148227_b.jpg,http://pic23.nipic.com/20120814/5914324_155903179106_2.jpg,http://pic40.nipic.com/20140403/8614226_162017444195_2.jpg];$picKey array_rand($mmpic); //随机返回一张图片$ws-push($frame-fd, file_get_contents($mmpic[$picKey]), WEBSOCKET_OPCODE_BINARY);} else {$ws-push($frame-fd, $this-reply($frame-data));}}private function reply($str) {$str mb_strtolower($str);switch ($str) {case hello:$res Hello, Friend.;break;case fuck:$res Fuck bitch.;break;case ping:$res PONG.;break;case time:$res date(H:i:s);break;default:$res $str;break;}return $res;}
Copy
将上面代码加入到Chat.php中用来处理接收消息并响应回复。响应回复的内容可以根据实际情况修改本代码只是用来演示。
启动服务端
在public/目录下建立chatServer.php代码如下
require dirname(__DIR__) . /vendor/autoload.php;use Shanhubei\Swoole\Chat;$opt [daemonize true
];
$ws new Chat($opt);
$ws-start();
Copy
然后运行以下代码启动服务端php chatServer.php 如果一切正常你可以netstat -lntp看一下系统会监听进程名为swooleChat端口为9504的服务。
启动客户端
我们使用HTML5的websocket客户端来连接服务端本地建立wsClient.html
!DOCTYPE html
html
headmeta charsetutf-8meta http-equivX-UA-Compatible contentIEedgemeta nameviewport contentwidthdevice-width,initial-scale1,maximum-scale1,user-scalablenotitleClient/titlelink relstylesheet hrefhttps://cdn.bootcss.com/bootstrap/3.3.5/css/bootstrap.min.csslink relstylesheet hrefcss/chat.css
/head
bodydiv idchat-wrapdiv idresult/divul classchat-threadli classyouimg classhead srcimages/head1.jpg altpAre we meeting today?/p/lili classyouimg classhead srcimages/head1.jpg altpyes/p/lili classmeimg classhead srcimages/head1.jpg altp一部分保持在行尾另一部分换到下一行。/p/lili classyouimg classhead srcimages/head1.jpg altpyes/p/lili classyouimg classhead srcimages/head1.jpg altpyes/p/li/ul/divdiv classsendform actioninput typetext classform-control idm autocompleteoff placeholder请输入内容button typesubmit classbtn btn-info发送/button/form/div
!-- divdiv idresult/divform classform-inline actiondiv classform-groupinput typetext classform-control idm autocompleteoff placeholder请输入内容/divbutton typesubmit classbtn btn-info发送/button/form
/div --
script srchttps://cdn.bootcss.com/jquery/2.2.4/jquery.min.js/script
script
if (WebSocket in window) {var ws new WebSocket(ws://192.168.3.105:9504);var result document.querySelector(#result);var chatthread document.querySelector(.chat-thread);chatthread.scrollTop chatthread.scrollHeight;ws.onopen function() {result.innerHTML 已连接上;$(#result).show().html(已连接上).fadeOut(1500);console.log(已连接上);}document.querySelector(form).onsubmit function(e) {var msg document.querySelector(#m).value;ws.send(msg);$(.chat-thread).append(li classmeimg classhead srcimages/head1.jpg altpmsg/p/li);chatthread.scrollTop chatthread.scrollHeight;document.querySelector(#m).value ;return false;}ws.onmessage function(e) {if(e.data instanceof Blob) {// var img document.createElement(img);// img.src window.URL.createObjectURL(e.data);// result.appendChild(img);// var d window.URL.createObjectURL(e.data);// console.log(d);var img img srcwindow.URL.createObjectURL(e.data) width180/;$(.chat-thread).append(li classyouimg classhead srcimages/head1.jpg altpimg/p/li);}else {// var p document.createElement(p);// p.innerHTML e.data;// result.appendChild(p);$(.chat-thread).append(li classyouimg classhead srcimages/head1.jpg altpe.data/p/li);}chatthread.scrollTop chatthread.scrollHeight;}ws.onclose function() {console.log(连接已关闭);}
} else {alert(您的浏览器不支持 WebSocket);
}
/script
/body
/html
Copy
然后用浏览器打开wsClient.html你可以看到一个聊天窗口一开始会提示连接成功然后你可以在输入框中输入你想说的话如“美女”等等。
三、使用Systemctl管理Swoole服务
配置Swoole服务
有了Systemctl我们可以轻松配置我们的Swoole服务下面以Swoole聊天服务为例
首先在/usr/lib/systemd/system/目录下新建文件swoolechat.service并加入以下代码
[Unit]
DescriptionSwoole Chat Server
Afternetwork.target syslog.target[Service]
Typeforking
LimitNOFILE65535
ExecStart/usr/local/php/bin/php /home/web/swoole/public/chatServer.php
ExecReload/bin/kill -USR1 $MAINPID
Restartalways[Install]
WantedBymulti-user.target graphical.target
Copy
然后保存好文件并使用如下命令重新载入所有的[Unit]文件确保我们添加进去的service能被系统加载并生效。
systemctl daemon-reload
Copy
验证
现在我们来验证服务首先启动swoole服务
systemctl start swoolechat.service
Copy
然后使用以下命令查看swoole服务是否正常:
systemctl status swoolechat.service
Copy
四、使用Swoole实现毫秒级定时任务
接着服务端代码 public\taskServer.php require dirname(__DIR__) . /vendor/autoload.php;use Shanhubei\Swoole\Task;$opt [daemonize false
];
$ser new Task($opt);
$ser-start();
Copy
客户端代码 public\taskClient.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, 9506 , 1) ) {echo Error: {$this-client-errMsg}[{$this-client-errCode}]\n;}fwrite(STDOUT, 请输入消息 Please input msg);$msg trim(fgets(STDIN));$this-client-send( $msg );$message $this-client-recv();echo Get Message From Server:{$message}\n;}
}$client new Client();
$client-connect();
Copy
验证效果
1.启动服务端
php taskServer.php
Copy
2.客户端输入
另开命令行窗口执行
[rootlocalhost public]# php taskClient.php
请输入消息 Please input msghello
Get Message From Server:{result:success}
Copy
五、使用Websocket上传文件
服务端
我们继续使用Swoole实验室1-使用Composer构建项目构建好的项目新建文件\src\app\Uploader.php
namespace Shanhubei\Swoole;
use swoole_websocket_server;class Uploader
{protected $ws;protected $host 0.0.0.0;protected $port 9505;// 进程名称protected $taskName swooleUploader;// PID路径protected $pidFile /run/swooleUploader.pid;// 设置运行时参数protected $options [worker_num 4, //worker进程数,一般设置为CPU数的1-4倍 daemonize true, //启用守护进程log_file /data/logs/uploadswoole.log, //指定swoole错误日志文件log_level 3, //日志级别 范围是0-50-DEBUG1-TRACE2-INFO3-NOTICE4-WARNING5-ERRORdispatch_mode 1, //数据包分发策略,1-轮询模式];public function __construct($options []){$this-ws new swoole_websocket_server($this-host, $this-port);if (!empty($options)) {$this-options array_merge($this-options, $options);}$this-ws-set($this-options);$this-ws-on(open, [$this, onOpen]);$this-ws-on(message, [$this, onMessage]);$this-ws-on(close, [$this, onClose]);}public function start(){// Run worker$this-ws-start();}public function onOpen(swoole_websocket_server $ws, $request){// 设置进程名cli_set_process_title($this-taskName);//记录进程id,脚本实现自动重启$pid {$ws-master_pid}\n{$ws-manager_pid};file_put_contents($this-pidFile, $pid);echo server: handshake success with fd{$request-fd}\n;$msg {msg: connect ok};$ws-push($request-fd, $msg);}public function onMessage(swoole_websocket_server $ws, $frame){$opcode $frame-opcode;if ($opcode 0x08) {echo Close frame received: Code {$frame-code} Reason {$frame-reason}\n;} else if ($opcode 0x1) {echo Text string\n;} else if ($opcode 0x2) {echo Binary data\n; //} else {echo Message received: {$frame-data}\n;}$filename ./files/aaa.jpg;file_put_contents($filename, $frame-data);echo file path : {$filename}\n;$ws-push($frame-fd, upload success);}public function onClose($ws, $fid){echo client {$fid} closed\n;foreach ($ws-connections as $fd) {$ws-push($fd, $fid. 已断开);}}
}
Copy
$frame-opcodeWebSocket的OpCode类型可以通过它来判断传输的数据是文本内容还是二进制数据。
新建public/uploadServer.php用于启动服务端脚本 require dirname(__DIR__) . /vendor/autoload.php;use Shanhubei\Swoole\Uploader;$opt [daemonize false
];
$ws new Uploader($opt);
$ws-start();
Copy
客户端
在本地站点建立客户端文件upload.html。只需在页面中放置一个文件选择控件和一个用于输出上传信息的div#log。
input typefile idmyFile
div idlog/div
Copy
当选择好本地文件后触发onchange事件这个时候客户端尝试与服务端建立websocket连接然后开始读取本地文件读取完成后将数据发送给服务端。
$(#myFile).on(change, function(event) {var ws new WebSocket(ws://192.168.3.106:9505);ws.onopen function() {log(已连接上);}ws.onmessage function(e) {log(收到服务器消息: e.data \n);if (e.data connect ok) {log(开始上传文件);} if (e.data upload success) {log(上传完成);ws.close();} else {var file document.getElementById(myFile).files[0];var reader new FileReader();reader.readAsArrayBuffer(file);reader.onload function(e) {ws.send(e.target.result);log(正在上传数据...);}}}ws.onclose function() {console.log(连接已关闭);log(连接已关闭);}
});
//在消息框中打印内容
function log(text) {$(#log).append(textbr/);
}
Copy
这里讲一下HTML5的FileReader 对象FileReader允许Web应用程序异步读取存储在用户计算机上的文件(或原始数据缓冲区)的内容使用 File 或 Blob 对象指定要读取的文件或数据。FileReader提供了几种读取文件的方法
reader.readAsArrayBuffer(file|blob)用于启动读取指定的 Blob 或 File 内容。读取文件后会在内存中创建一个ArrayBuffer对象(二进制缓冲区)将二进制数据存放在其中。当读取操作完成时readyState 变成 DONE(已完成)并触发 loadend 事件同时 result 属性中将包含一个 ArrayBuffer 对象以表示所读取文件的数据。通过此方式可以直接在网络中传输二进制内容。此外对于大文件我们可以分段读取二进制内容上传。reader.readAsDataURL(file|blob)该方法会读取指定的 Blob 或 File 对象。读取操作完成的时候readyState 会变成已完成(DONE)并触发 loadend 事件同时 result 属性将包含一个data:URL格式的字符串(base64编码)以表示所读取文件的内容。FileReader.readAsText(file|blob)可以将 Blob 或者 File 对象转根据特殊的编码格式转化为内容(字符串形式)。当转化完成后 readyState 这个参数就会转换 为 done 即完成态 event(“loadend”) 挂载的事件会被触发并可以通过事件返回的形参得到中的 FileReader.result 属性得到转化后的结果。FileReader.readAsBinaryString()读取文件内容为二进制字符串已废除不要用了。
运行服务端
php uploadServer.php
Copy
运行客户端
在本地站点目录打开upload.html