安裝swoole
pecl install swoole
修改PHP配置文件php.ini加入
extension=swoole.so
有可能不需要人工去加,安裝時自動加入進來了,
查看swoole擴展是否安裝好
/usr/local/php/bin/php -m
配制列表里面如果有swoole的話,恭喜你安裝並配置swoole成功。
在index.php同級目錄下面新新建ws.php文件,文件內容以下
<?php class Ws { CONST HOST = "0.0.0.0"; CONST PORT = 9501; public $ws = null; public function __construct() { $this->ws = new swoole_websocket_server(self::HOST, self::PORT); $this->ws->set( [ 'worker_num' => 4,//打開的進程數 'daemonize'=>0,//1守護進程,在后台一直運行 ] ); //websocket繼承於http_service,所以擁有http_service服務器的所有函數 //http_service函數, $this->ws->on("start", [$this, 'onStart']); $this->ws->on("workerstart", [$this, 'onWorkerStart']);//此事件在Worker進程/Task進程啟動時發生。 $this->ws->on("request", [$this, 'onRequest']); $this->ws->on("task", [$this, 'onTask']); $this->ws->on("finish", [$this, 'onFinish']); //websocket函數 $this->ws->on("open", [$this, 'onOpen']); $this->ws->on("message", [$this, 'onMessage']); $this->ws->on("close", [$this, 'onClose']); $this->ws->start();//開啟 } /** * @param $server */ public function onStart($server) { swoole_set_process_name("websocket");//修改進程名稱,非必要 } /** * @param $server * @param $worker_id */ public function onWorkerStart($server, $worker_id) { //swoole是cli運行,執行地址path會無法正確找到,所以把base.php里面定義的常量提出來,設置為假, //注意:記住把源代碼base.php里面的define('IS_CLI',false)代碼去掉(常量不能重復定義),在index.php里面加入代碼:define('IS_CLI', PHP_SAPI == 'cli' ? true : false); define('IS_CLI',false);// //當進程運行時,把框架代碼加載進來 // 定義應用目錄 define('APP_PATH', __DIR__ . '/../application/'); // 加載框架里面的文件 require __DIR__ . '/../thinkphp/base.php'; } /** * request回調 * 當請求過來時,會調用此方法,調用thinkphp真正的執行邏輯 * @param $request * @param $response */ public function onRequest($request, $response) { //因為這些全局變量會在進程的內存里面不變,所有每次請求到來先清空值。 if($request->server['request_uri'] == '/favicon.ico') { $response->status(404); $response->end(); return ; } $_SERVER = []; if(isset($request->server)) { foreach($request->server as $k => $v) { $_SERVER[strtoupper($k)] = $v; } } if(isset($request->header)) { foreach($request->header as $k => $v) { $_SERVER[strtoupper($k)] = $v; } } $_GET = []; if(isset($request->get)) { foreach($request->get as $k => $v) { $_GET[$k] = $v; } } $_FILES = []; if(isset($request->files)) { foreach($request->files as $k => $v) { $_FILES[$k] = $v; } } $_POST = []; if(isset($request->post)) { foreach($request->post as $k => $v) { $_POST[$k] = $v; } } $_POST['http_server'] = $this->ws;//把對像傳過去 ob_start(); try { // 執行應用並響應 think\App::run()->send(); }catch (\Exception $e) { // todo echo $e->getMessage(); } $res = ob_get_contents(); ob_end_clean(); $response->end($res); } /** * 監聽ws連接事件 * @param $ws * @param $request */ public function onOpen($ws, $request) { $ws->push($request->fd, "hello, welcome\n");//發送消息給客戶端 /* 與thinkphp框架結合 think\App::run();//如果不執行這行代碼,框架里面很多功能用不了 //執類指定類里面的指定方法 $obj=new \app\index\controller\Login(); $obj->action(); */ } /** * 接收客戶端傳過來的消息事件 * @param $ws * @param $frame */ public function onMessage($ws, $frame) { $msg=$frame->data;//接收客戶端傳過來的消息 $ws->push($frame->fd, "server-push:".date("Y-m-d H:i:s")); } /** * ws客戶端關閉時調用事件 * @param $ws * @param $fd */ public function onClose($ws, $fd) { echo "clientid:{$fd}\n"; } /** * @param $serv * @param $taskId * @param $workerId * @param $data */ public function onTask($serv, $taskId, $workerId, $data) { // 分發 task 任務機制,讓不同的任務 走不同的邏輯 $obj = new app\common\lib\task\Task; $method = $data['method']; $flag = $obj->$method($data['data'], $serv); /*$obj = new app\common\lib\ali\Sms(); try { $response = $obj::sendSms($data['phone'], $data['code']); }catch (\Exception $e) { // todo echo $e->getMessage(); }*/ return $flag; // 告訴worker } /** * @param $serv * @param $taskId * @param $data */ public function onFinish($serv, $taskId, $data) { echo "taskId:{$taskId}\n"; echo "finish-data-sucess:{$data}\n"; } } new Ws();
因為tp里面的全局變量會在進程的內存里面不變,會導致執行地址path不更新,需要修改源代碼
修改框架源代碼thinkphp/library/think/Request.php,兩處地方,如下2圖:
上面是服務端websocket代碼,下面是客戶端JS
<script> var wsServer = 'ws://193.112.27.236:9501/index/login/a?cc=1'; //websocket服務端地址,記住ws://不能去掉 var websocket = new WebSocket(wsServer); websocket.onopen = function (evt) { console.log("Connected to WebSocket server."); websocket.send(1111);//發送數據給服務器 }; //服務端關閉時調用 websocket.onclose = function (evt) { console.log("Disconnected"); }; //服務端向客戶端發送消息時調用 websocket.onmessage = function (evt) { console.log('Retrieved data from server: ' + evt.data); }; //服務端報錯時調用 websocket.onerror = function (evt, e) { console.log('Error occured: ' + evt.data); }; </script>
注意:linux上面運行開啟服務時
php ws.php
以上命令可能會有問題,因為cli模式下運行的php 可能跟你項目運行的php版本跟配置文件不一樣
可以使用以下命令來保證准確:
查看是否啟動成功
修改代碼之后,需要殺死進程,重新啟動