摘要:概述這是關于學習的第六篇文章整合成一個小框架。相關配置,在文件夾。代碼放不全,就放一個主要的文件吧。當然我自己也會繼續完善它,后期的一些新知識點會集成到這里面,做成自己迭代的小項目。初版比較糙,不喜勿噴。后期會新增需要源碼的,加我微信吧。
概述
這是關于 Swoole 學習的第六篇文章:Swoole 整合成一個小框架。
第五篇:Swoole 多協議 多端口 的應用
第四篇:Swoole HTTP 的應用
第三篇:Swoole WebSocket 的應用
第二篇:Swoole Task 的應用
第一篇:Swoole Timer 的應用
寫了關于 Swoole 入門的 5 篇文章后,增加了不少的關注者,也得到了一些大佬的鼓勵,也有很多關注者都加了微信好友,交流之后發現一些朋友比我優秀還比我努力,也得到了一些大佬的建議。
發現持續寫文章真的不是件容易的事,擔心別人認為沒價值,擔心想法太幼稚或有漏洞被別人笑話,擔心腦子里墨水太少,寫不出來... 知道自己思路還不夠清晰,邏輯還不夠嚴謹,告訴自己沒關系,一些都會好起來的,逆境才能成長嘛,敢寫就是好的開始,以此來激勵自己持續的學習和思考。
跑題了,說回正題。
這篇文章其實是讀者的小小要求,事情是這樣的:
讀者:“亮哥,看了你的文章很有收獲,將文章 Demo 放在本地直接就能運行了,太感謝了”
本人:“哈哈。。。有收獲就好,感謝支持 ~ ”
讀者:“我有一個小小的要求,現在每個文件都是獨立的,我想部署到生產環境,想操作上更便捷,有日志...”
本人:“你說的不是框架嗎?現在有很多現成的,看 Swoole 官網推薦的 Swoft、EasySwoole、MixPHP 等。詳細的參考這個地址:https://wiki.swoole.com/wiki/...”
讀者:“看了,發現文件太多了,看不懂,你能幫忙講解下嗎?”
本人:“What?我也是入門呀,要不我搞個簡單的輪子吧”
......
于是就有了這篇文章,正好也是對前面 5 篇文章的復習吧。
效果命令如下:
php index.php 可以查看到上圖
php index.php start 開啟服務(Debug模式)
php index.php start -d 開啟服務(Daemon模式)
php index.php status 查看服務狀態
php index.php reload 服務熱加載
php index.php stop 關閉服務
index.php 這是文件名稱,大家叫什么都可以。
目錄結構如下:
├─ controller │ ├── ... ├─ client │ ├─ websocket │ ├── ... │ ├─ tcp │ ├── ... ├─ server │ ├─ config │ ├── config.php │ ├─ core │ ├── Common.php │ ├── Core.php │ ├── HandlerException.php │ ├─ log -- 需要 讀/寫 權限 │ ├── ... ├─ index.php
目前就這幾個文件,后期研究新的知識點會直接集成到這里面。
說說實現了什么:
1、啟動了 WebSocket、HTTP、TCP、UDP 等服務。
2、WebSocket 例子,在 client/websocket 文件夾,實現了視頻彈幕。
3、HTTP 例子,在瀏覽器直接訪問:http://ip:port,邏輯代碼在 controller 文件夾。
4、TCP 例子,在 client/tcp 文件夾。
5、UDP 例子,直接運行 netcat -u ip port 即可。
6、相關配置,在 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模式開啟服務 |".PHP_EOL; echo "| 2. start -d 以daemon模式開啟服務 |".PHP_EOL; echo "| 3. status 查看服務狀態 |".PHP_EOL; echo "| 4. reload 熱加載 |".PHP_EOL; echo "| 5. stop 關閉服務 |".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("客戶端關閉"); } catch(Exception $e) { } }); self::$serv->on("Shutdown", function ($serv) { echo output("服務關閉"); }); 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("暫無啟動的服務"); 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("暫無啟動的服務"); 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("暫無啟動的服務"); 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("服務關閉成功"); break; } else { if (time() - $time > 5) { echo output("服務關閉失敗,請重試"); 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("啟動/關閉", 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; //}); } }小結
耗費了 3 個晚上的時間,終于完成了一個初版,比較初級,希望可以給入門的同學一個參考吧。
當然我自己也會繼續完善它,后期的一些新知識點會集成到這里面,做成自己迭代的小項目。
初版比較糙,不喜勿噴。
后期會新增:
RPC
Coroutine - MySQL
Coroutine - Redis
Process
...
需要源碼的,加我微信吧。(菜單-> 加我微信-> 掃我)
推薦閱讀系統的講解 - SSO 單點登錄
系統的講解 - PHP WEB 安全防御
系統的講解 - PHP 緩存技術
系統的講解 - PHP 接口簽名驗證
系統的講解 - PHP 浮點數高精度運算
本文歡迎轉發,轉發請注明作者和出處,謝謝!
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/31479.html
摘要:概述這是關于入門學習的第十篇文章壓測性能。測試機上安裝的虛擬機系統內存數量核數數量大小代碼壓測腳本并發量請求量壓測結果第次第次第次以上是壓測結果,供參考。小結通過這個壓測結果,表明的執行效率是杠杠的當然還有一些參數是可以調優的,比如等。 概述 這是關于 Swoole 入門學習的第十篇文章:壓測 swoole_websocket_server 性能。 第九篇:Swoole Redis ...
摘要:概述這是關于入門學習的第八篇文章連接池的實現。開始今天的文章,這篇文章實現了連接池,代碼是在的實現文章的基礎上進行開發的。 概述 這是關于 Swoole 入門學習的第八篇文章:Swoole MySQL 連接池的實現。 第七篇:Swoole RPC 的實現 第六篇:Swoole 整合成一個小框架 第五篇:Swoole 多協議 多端口 的應用 第四篇:Swoole HTTP 的應用 第三...
摘要:概述這是關于學習的第七篇文章的實現。還有一些大佬加了微信,可能是出于對晚輩的提攜吧,偷偷告訴你,從大佬的朋友圈能學到很多東西。就到這了,上面的需要源碼的,加我微信。 概述 這是關于 Swoole 學習的第七篇文章:Swoole RPC 的實現。 第六篇:Swoole 整合成一個小框架 第五篇:Swoole 多協議 多端口 的應用 第四篇:Swoole HTTP 的應用 第三篇:Swo...
摘要:自發布以來,終于確定了發展的路線,最終還是和走在了一起,并且基于提供強大的性能支持。不同于,僅提供最基礎的核心主干,其他均由開發者自助組裝框架不會過度整合太多不必要的組件,現在不會,未來也不會。 自 3.0 發布以來,FastD 終于確定了發展的路線,最終還是和 Swoole 走在了一起,并且基于 Swoole 提供強大的性能支持。項目地址: FastD 優勢: 簡單,靈活,開發服務...
閱讀 3561·2023-04-26 02:10
閱讀 1299·2021-11-22 15:25
閱讀 1668·2021-09-22 10:02
閱讀 907·2021-09-06 15:02
閱讀 3469·2019-08-30 15:55
閱讀 600·2019-08-30 13:58
閱讀 2775·2019-08-30 12:53
閱讀 3042·2019-08-29 12:38