摘要:概述這是關(guān)于學(xué)習(xí)的第六篇文章整合成一個小框架。相關(guān)配置,在文件夾。代碼放不全,就放一個主要的文件吧。當(dāng)然我自己也會繼續(xù)完善它,后期的一些新知識點會集成到這里面,做成自己迭代的小項目。初版比較糙,不喜勿噴。后期會新增需要源碼的,加我微信吧。
概述
這是關(guān)于 Swoole 學(xué)習(xí)的第六篇文章:Swoole 整合成一個小框架。
第五篇:Swoole 多協(xié)議 多端口 的應(yīng)用
第四篇:Swoole HTTP 的應(yīng)用
第三篇:Swoole WebSocket 的應(yīng)用
第二篇:Swoole Task 的應(yīng)用
第一篇:Swoole Timer 的應(yīng)用
寫了關(guān)于 Swoole 入門的 5 篇文章后,增加了不少的關(guān)注者,也得到了一些大佬的鼓勵,也有很多關(guān)注者都加了微信好友,交流之后發(fā)現(xiàn)一些朋友比我優(yōu)秀還比我努力,也得到了一些大佬的建議。
發(fā)現(xiàn)持續(xù)寫文章真的不是件容易的事,擔(dān)心別人認為沒價值,擔(dān)心想法太幼稚或有漏洞被別人笑話,擔(dān)心腦子里墨水太少,寫不出來... 知道自己思路還不夠清晰,邏輯還不夠嚴謹,告訴自己沒關(guān)系,一些都會好起來的,逆境才能成長嘛,敢寫就是好的開始,以此來激勵自己持續(xù)的學(xué)習(xí)和思考。
跑題了,說回正題。
這篇文章其實是讀者的小小要求,事情是這樣的:
讀者:“亮哥,看了你的文章很有收獲,將文章 Demo 放在本地直接就能運行了,太感謝了”
本人:“哈哈。。。有收獲就好,感謝支持 ~ ”
讀者:“我有一個小小的要求,現(xiàn)在每個文件都是獨立的,我想部署到生產(chǎn)環(huán)境,想操作上更便捷,有日志...”
本人:“你說的不是框架嗎?現(xiàn)在有很多現(xiàn)成的,看 Swoole 官網(wǎng)推薦的 Swoft、EasySwoole、MixPHP 等。詳細的參考這個地址:https://wiki.swoole.com/wiki/...”
讀者:“看了,發(fā)現(xiàn)文件太多了,看不懂,你能幫忙講解下嗎?”
本人:“What?我也是入門呀,要不我搞個簡單的輪子吧”
......
于是就有了這篇文章,正好也是對前面 5 篇文章的復(fù)習(xí)吧。
效果命令如下:
php index.php 可以查看到上圖
php index.php start 開啟服務(wù)(Debug模式)
php index.php start -d 開啟服務(wù)(Daemon模式)
php index.php status 查看服務(wù)狀態(tài)
php index.php reload 服務(wù)熱加載
php index.php stop 關(guān)閉服務(wù)
index.php 這是文件名稱,大家叫什么都可以。
目錄結(jié)構(gòu)如下:
├─ controller │ ├── ... ├─ client │ ├─ websocket │ ├── ... │ ├─ tcp │ ├── ... ├─ server │ ├─ config │ ├── config.php │ ├─ core │ ├── Common.php │ ├── Core.php │ ├── HandlerException.php │ ├─ log -- 需要 讀/寫 權(quán)限 │ ├── ... ├─ index.php
目前就這幾個文件,后期研究新的知識點會直接集成到這里面。
說說實現(xiàn)了什么:
1、啟動了 WebSocket、HTTP、TCP、UDP 等服務(wù)。
2、WebSocket 例子,在 client/websocket 文件夾,實現(xiàn)了視頻彈幕。
3、HTTP 例子,在瀏覽器直接訪問:http://ip:port,邏輯代碼在 controller 文件夾。
4、TCP 例子,在 client/tcp 文件夾。
5、UDP 例子,直接運行 netcat -u ip port 即可。
6、相關(guān)配置,在 server/config 文件夾。
代碼放不全,就放一個主要的文件吧(Core.php)。
3) { echo PHP_EOL; echo "----------------------------------------".PHP_EOL; echo "| Swoole |".PHP_EOL; echo "|--------------------------------------|".PHP_EOL; echo "| USAGE: php index.php commond |".PHP_EOL; echo "|--------------------------------------|".PHP_EOL; echo "| 1. start 以debug模式開啟服務(wù) |".PHP_EOL; echo "| 2. start -d 以daemon模式開啟服務(wù) |".PHP_EOL; echo "| 3. status 查看服務(wù)狀態(tài) |".PHP_EOL; echo "| 4. reload 熱加載 |".PHP_EOL; echo "| 5. stop 關(guān)閉服務(wù) |".PHP_EOL; echo "----------------------------------------".PHP_EOL; echo PHP_EOL; exit; } } protected static function parseCommand() { global $argv; $command = $argv[1]; $option = isset( $argv[2] ) ? $argv[2] : "" ; switch ($command) { case "start": if ($option === "-d") { //以daemon形式啟動 get_config(["set@daemonize" => true]); } self::workerStart(); break; case "status": self::workerStatus(); break; case "reload": self::workerReload(); break; case "stop": self::workerStop(); break; default: echo "Bad Command.".PHP_EOL; } } protected static function workerStart() { $config = get_config(); self::$serv = new swoole_websocket_server($config["ip"], $config["websocket_port"]); self::$serv->set($config["set"]); self::$serv->on("Start", function ($serv) use ($config) { $start = new OnStart(); $start::run($serv, $config); }); self::$serv->on("ManagerStart", function ($serv) use ($config) { $manager_start = new OnManagerStart(); $manager_start::run($serv, $config); }); self::$serv->on("WorkerStart", function ($serv, $worker_id) use ($config) { $worker_start = new OnWorkerStart(); $worker_start::run($serv, $worker_id, $config); }); //TCP $tcp = self::$serv->listen($config["ip"], $config["tcp_port"], SWOOLE_SOCK_TCP); $tcp->set($config["tcp_set"]); $tcp->on("Receive", function ($serv, $fd, $reactor_id, $data) { $receive = new OnReceive(); $receive::run($serv, $fd, $reactor_id, $data); }); //UDP $udp = self::$serv->listen($config["ip"], $config["udp_port"], SWOOLE_SOCK_UDP); $udp->set($config["udp_set"]); $udp->on("Packet", function ($serv, $data, $client_info) { $packet = new OnPacket(); $packet::run($serv, $data, $client_info); }); self::$serv->on("Task", function ($serv, $task_id, $src_worker_id, $data) use ($config) { $task = new OnTask(); $dataArr = json_decode($data, true); switch ($dataArr["server"]) { case "tcp": $task::tcp_task_run($serv, $task_id, $src_worker_id, $data); break; case "ws": $task::ws_task_run($serv, $task_id, $src_worker_id, $data); break; } }); self::$serv->on("Open", function ($serv, $request) { echo output("onOpen: handshake success with fd={$request->fd}"); }); self::$serv->on("Message", function ($serv, $frame) { $message = new OnMessage(); $message::run($serv, $frame); }); self::$serv->on("Request", function ($request, $response) { $req = new OnRequest(); $req::run($request, $response); }); self::$serv->on("Finish", function ($serv, $task_id, $data) { $finish = new OnFinish(); $finish::run($serv, $task_id, $data); }); self::$serv->on("Close", function ($serv, $fd, $reactor_id){ try { echo output("客戶端關(guān)閉"); } catch(Exception $e) { } }); self::$serv->on("Shutdown", function ($serv) { echo output("服務(wù)關(guān)閉"); }); self::showProcessUI(); self::$serv->start(); } protected static function workerStatus() { $config = get_config(); if (!file_exists($config["master_pid_file"]) || !file_exists($config["manager_pid_file"]) || !file_exists($config["worker_pid_file"]) ) { echo output("暫無啟動的服務(wù)"); return false; } self::showProcessUI($config); $masterPidString = trim(@file_get_contents($config["master_pid_file"])); $masterPidArr = explode( "-", $masterPidString); echo str_pad("Master", 18, " ", STR_PAD_BOTH ). str_pad($config["master_process_name"], 26, " ", STR_PAD_BOTH ). str_pad($masterPidArr[0], 16, " ", STR_PAD_BOTH ). str_pad($masterPidArr[1], 16, " ", STR_PAD_BOTH ). str_pad($masterPidArr[2], 16, " ", STR_PAD_BOTH ).PHP_EOL; $managerPidString = trim(@file_get_contents($config["manager_pid_file"])); $managerPidArr = explode( "-", $managerPidString); echo str_pad("Manager", 20, " ", STR_PAD_BOTH ). str_pad($config["manager_process_name"], 24, " ", STR_PAD_BOTH ). str_pad($managerPidArr[0], 16, " ", STR_PAD_BOTH ). str_pad($managerPidArr[1], 16, " ", STR_PAD_BOTH ). str_pad($managerPidArr[2], 16, " ", STR_PAD_BOTH ).PHP_EOL; $workerPidString = rtrim(@file_get_contents($config["worker_pid_file"]), "|" ); $workerPidArr = explode( "|", $workerPidString ); if (isset($workerPidArr) && !empty($workerPidArr)) { foreach ($workerPidArr as $key => $val) { $v = explode( "-", $val); echo str_pad("Worker", 18, " ", STR_PAD_BOTH ). str_pad($config["worker_process_name"], 26, " ", STR_PAD_BOTH ). str_pad($v[0], 16, " ", STR_PAD_BOTH ). str_pad($v[1], 16, " ", STR_PAD_BOTH ). str_pad($v[2], 16, " ", STR_PAD_BOTH ).PHP_EOL; } } $taskPidString = rtrim(@file_get_contents($config["task_pid_file"]), "|" ); $taskPidArr = explode( "|", $taskPidString ); if (isset($taskPidArr) && !empty($taskPidArr)) { foreach ($taskPidArr as $key => $val) { $v = explode( "-", $val); echo str_pad("Task", 18, " ", STR_PAD_BOTH ). str_pad($config["task_process_name"], 24, " ", STR_PAD_BOTH ). str_pad($v[0], 20, " ", STR_PAD_BOTH ). str_pad($v[1], 12, " ", STR_PAD_BOTH ). str_pad($v[2], 20, " ", STR_PAD_BOTH ).PHP_EOL; } } } protected static function workerReload() { $config = get_config(); if (!file_exists($config["master_pid_file"])) { echo output("暫無啟動的服務(wù)"); return false; } $masterPidString = trim(file_get_contents($config["master_pid_file"])); $masterPidArr = explode( "-", $masterPidString); if (!swoole_process::kill($masterPidArr[0], 0)) { echo output("PID:{$masterPidArr[0]} 不存在"); return false; } swoole_process::kill($masterPidArr[0], SIGUSR1); @unlink($config["worker_pid_file"]); @unlink($config["task_pid_file"]); echo output("熱加載成功"); return true; } protected static function workerStop() { $config = get_config(); if (!file_exists($config["master_pid_file"])) { echo output("暫無啟動的服務(wù)"); return false; } $masterPidString = trim(file_get_contents($config["master_pid_file"])); $masterPidArr = explode( "-", $masterPidString); if (!swoole_process::kill($masterPidArr[0], 0)) { echo output("PID:{$masterPidArr[0]} 不存在"); return false; } swoole_process::kill($masterPidArr[0]); $time = time(); while (true) { usleep(2000); if (!swoole_process::kill($masterPidArr[0], 0)) { unlink($config["master_pid_file"]); unlink($config["manager_pid_file"]); unlink($config["worker_pid_file"]); unlink($config["task_pid_file"]); echo output("服務(wù)關(guān)閉成功"); break; } else { if (time() - $time > 5) { echo output("服務(wù)關(guān)閉失敗,請重試"); break; } } } return true; } protected static function showProcessUI() { $config = get_config(); if ($config["set"]["daemonize"] == true) { return false; } echo str_pad("-", 90, "-", STR_PAD_BOTH) . PHP_EOL; echo "|" . str_pad("啟動/關(guān)閉", 92, " ", STR_PAD_BOTH) . "|" . PHP_EOL; echo str_pad("-", 90, "-", STR_PAD_BOTH) . PHP_EOL; echo str_pad("Start success.", 50, " ", STR_PAD_BOTH) . str_pad("php index.php stop", 50, " ", STR_PAD_BOTH) . PHP_EOL; echo str_pad("-", 90, "-", STR_PAD_BOTH) . PHP_EOL; echo "|" . str_pad("版本信息", 92, " ", STR_PAD_BOTH) . "|" . PHP_EOL; echo str_pad("-", 90, "-", STR_PAD_BOTH) . PHP_EOL; echo str_pad("Swoole Version:" . SWOOLE_VERSION, 50, " ", STR_PAD_BOTH) . str_pad("PHP Version:" . PHP_VERSION, 50, " ", STR_PAD_BOTH) . PHP_EOL; echo str_pad("-", 90, "-", STR_PAD_BOTH) . PHP_EOL; echo "|" . str_pad("IP 信息", 90, " ", STR_PAD_BOTH) . "|" . PHP_EOL; echo str_pad("-", 90, "-", STR_PAD_BOTH) . PHP_EOL; echo str_pad("IP:" . $config["ip"], 50, " ", STR_PAD_BOTH) . str_pad("PORT:" . $config["websocket_port"], 50, " ", STR_PAD_BOTH) . PHP_EOL; echo str_pad("-", 90, "-", STR_PAD_BOTH) . PHP_EOL; echo "|" . str_pad("進程信息", 92, " ", STR_PAD_BOTH) . "|" . PHP_EOL; echo str_pad("-", 90, "-", STR_PAD_BOTH) . PHP_EOL; echo str_pad("Swoole進程", 20, " ", STR_PAD_BOTH) . str_pad("進程別名", 30, " ", STR_PAD_BOTH) . str_pad("進程ID", 18, " ", STR_PAD_BOTH) . str_pad("父進程ID", 18, " ", STR_PAD_BOTH) . str_pad("用戶", 18, " ", STR_PAD_BOTH) . PHP_EOL; } protected static function signalHandler() { //TODO 未完成 //swoole_process::signal(SIGINT, function ($signal) { // echo $signal; // return; //}); } }小結(jié)
耗費了 3 個晚上的時間,終于完成了一個初版,比較初級,希望可以給入門的同學(xué)一個參考吧。
當(dāng)然我自己也會繼續(xù)完善它,后期的一些新知識點會集成到這里面,做成自己迭代的小項目。
初版比較糙,不喜勿噴。
后期會新增:
RPC
Coroutine - MySQL
Coroutine - Redis
Process
...
需要源碼的,加我微信吧。(菜單-> 加我微信-> 掃我)
推薦閱讀系統(tǒng)的講解 - SSO 單點登錄
系統(tǒng)的講解 - PHP WEB 安全防御
系統(tǒng)的講解 - PHP 緩存技術(shù)
系統(tǒng)的講解 - PHP 接口簽名驗證
系統(tǒng)的講解 - PHP 浮點數(shù)高精度運算
本文歡迎轉(zhuǎn)發(fā),轉(zhuǎn)發(fā)請注明作者和出處,謝謝!
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/31479.html
摘要:概述這是關(guān)于入門學(xué)習(xí)的第十篇文章壓測性能。測試機上安裝的虛擬機系統(tǒng)內(nèi)存數(shù)量核數(shù)數(shù)量大小代碼壓測腳本并發(fā)量請求量壓測結(jié)果第次第次第次以上是壓測結(jié)果,供參考。小結(jié)通過這個壓測結(jié)果,表明的執(zhí)行效率是杠杠的當(dāng)然還有一些參數(shù)是可以調(diào)優(yōu)的,比如等。 概述 這是關(guān)于 Swoole 入門學(xué)習(xí)的第十篇文章:壓測 swoole_websocket_server 性能。 第九篇:Swoole Redis ...
摘要:概述這是關(guān)于入門學(xué)習(xí)的第八篇文章連接池的實現(xiàn)。開始今天的文章,這篇文章實現(xiàn)了連接池,代碼是在的實現(xiàn)文章的基礎(chǔ)上進行開發(fā)的。 概述 這是關(guān)于 Swoole 入門學(xué)習(xí)的第八篇文章:Swoole MySQL 連接池的實現(xiàn)。 第七篇:Swoole RPC 的實現(xiàn) 第六篇:Swoole 整合成一個小框架 第五篇:Swoole 多協(xié)議 多端口 的應(yīng)用 第四篇:Swoole HTTP 的應(yīng)用 第三...
摘要:概述這是關(guān)于學(xué)習(xí)的第七篇文章的實現(xiàn)。還有一些大佬加了微信,可能是出于對晚輩的提攜吧,偷偷告訴你,從大佬的朋友圈能學(xué)到很多東西。就到這了,上面的需要源碼的,加我微信。 概述 這是關(guān)于 Swoole 學(xué)習(xí)的第七篇文章:Swoole RPC 的實現(xiàn)。 第六篇:Swoole 整合成一個小框架 第五篇:Swoole 多協(xié)議 多端口 的應(yīng)用 第四篇:Swoole HTTP 的應(yīng)用 第三篇:Swo...
摘要:自發(fā)布以來,終于確定了發(fā)展的路線,最終還是和走在了一起,并且基于提供強大的性能支持。不同于,僅提供最基礎(chǔ)的核心主干,其他均由開發(fā)者自助組裝框架不會過度整合太多不必要的組件,現(xiàn)在不會,未來也不會。 自 3.0 發(fā)布以來,F(xiàn)astD 終于確定了發(fā)展的路線,最終還是和 Swoole 走在了一起,并且基于 Swoole 提供強大的性能支持。項目地址: FastD 優(yōu)勢: 簡單,靈活,開發(fā)服務(wù)...
閱讀 3611·2023-04-26 02:10
閱讀 1397·2021-11-22 15:25
閱讀 1702·2021-09-22 10:02
閱讀 945·2021-09-06 15:02
閱讀 3505·2019-08-30 15:55
閱讀 635·2019-08-30 13:58
閱讀 2807·2019-08-30 12:53
閱讀 3092·2019-08-29 12:38