ThinkPHP 5.1 Swoole 快速上手指南
本篇內容主要講述了最新的think-swoole
擴充套件的使用。
本指南的目的不是為了讓你掌握
Swoole
開發,而且幫助你使用think-swoole
快速部署ThinkPHP5.1
應用到Swoole
的HttpServer
,以及使用快速啟動Swoole
服務,如果你需要了解Swoole
的具體用法和原理,請參考Swoole官方文件,說的比較詳細了。
本文的內容並不適用於ThinkPHP
5.0
及以下版本(5.0
或者5.1.18
之前版本的Swoole
的支援可以參考這裡) !
安裝Swoole
首先按照Swoole官網說明安裝swoole
擴充套件,推薦新手可以直接使用
sudo pecl install swoole
會安裝最新的穩定版(截至本文釋出最新版本是4.0.3
版本),如果你需要安裝某個版本,例如,如果你不需要使用協程功能,只需要安裝1.*
版本,可以使用:
sudo pecl install swoole-1.10.5
可以在這裡檢視所有的swoole版本。
安裝完成後,你可能需要在你的php.ini
中新增:
extension=swoole
最後,請確認你的php的swoole
模組已經支援。
php -m
如果你能夠看到swoole
在列表中,說明swoole
模組已經正常安裝了。
如果安裝過程中遇到問題,根據提示進行操作即可,或者自行百度,這裡不再贅述。
安裝think-swoole
接下來第二步是安裝think-swoole
擴充套件,本文中的內容以最新版本的擴充套件為例(可能部分功能老版本的擴充套件不支援),如果你的擴充套件版本較舊,請更新框架或者擴充套件版本。
think-swoole
是ThinkPHP官方釋出的swoole
擴充套件,從2.0+
版本完善了對Swoole
的支援。
ThinkPHP5+
的擴充套件都是基於Composer
安裝的,所以確認你已經安裝了Composer
。
如果你已經有自己的ThinkPHP5.1
專案了,為了使用最新的特性,建議更新到最新版本(V5.1.20+
),然後可以在應用根目錄下使用下面命令安裝擴充套件。
composer require topthink/think-swoole
會安裝最新的穩定版本的think-swoole
擴充套件。
如果你是第一次使用ThinkPHP5.1
,那麼可以先建立一個初始專案,然後再安裝擴充套件,依次執行下面的命令即可。
composer create-project topthink/think tp
cd tp
composer require topthink/think-swoole
啟動Swoole HTTP
服務
第一個場景(也是該擴充套件最重要的一個場景),畢竟大部分使用think-swoole
擴充套件的使用者都是在使用ThinkPHP開發網站或者專案,使用think-swoole
擴充套件可以讓你的產品直接部署到Swoole
上,並且享受下面的優勢:
- 無需對程式碼進行改造就能帶來效能的數倍提升;
- 可以在
Apache
/Nginx
等傳統WEB伺服器和Swoole
之間切換部署;
簡單點說,就是你可以在傳統模式下開發你的應用,然後直接部署到
Swoole
上執行,但無需針對Swoole
寫任何的處理程式碼。
安裝完擴充套件後,你什麼都不需要做,最簡單的就是直接在命令列(應用根目錄下面)下執行:
php think swoole
啟動成功後會顯示
Starting swoole http server...
Swoole http server started: <http://0.0.0.0:9501>
You can exit with `CTRL-C`
可以看到已經在0.0.0.0:9501
啟動一個HTTP Server服務端,下面我們可以直接訪問當前的應用。
http://localhost:9501
如果你之前已經有執行一個80埠的WEB服務,那麼可以比較下兩個頁面的區別。
如果你是剛建立的專案,那麼可以直接看到ThinkPHP5.1
的歡迎頁面。
否則你會看到你的專案首頁。
配置檔案
HTTPServer
的引數可以在應用配置目錄下的swoole.php
裡面配置,該檔案會在擴充套件安裝的時候自動生成(如果沒有則可以自己建立)。
擴充套件自帶的配置引數主要包括:
配置引數 | 描述 | 預設值 |
---|---|---|
host | 監聽地址 | 0.0.0.0 |
port | 監聽埠 | 9501 |
mode | 執行模式 | SWOOLE_PROCESS |
sock_type | Socket type | SWOOLE_SOCK_TCP |
app_path | 應用目錄(守護程序模式必須設定) | 自動識別 |
ssl | 是否啟用https | false |
file_monitor | 是否監控檔案更改(V2.0.9+) | false |
file_monitor_interval | 監控檔案間隔(秒)(V2.0.9+) | 2 |
file_monitor_path | 監控目錄 (V2.0.9+) | 預設監控application和config目錄 |
其它的
swoole
引數可以參考官方文件的配置引數,所有swoole
本身支援的配置引數都可以直接在swoole.php
中使用。
守護程序模式
如果需要使用守護程序模式執行,可以使用
php think swoole -d
或者在swoole.php
檔案中設定
'daemonize' => true
不過一定要記得,如果啟用守護程序模式,必須設定應用目錄app_path
(使用絕對路徑),否則會出錯。
'host' => '0.0.0.0', // 監聽地址
'port' => 9501, // 監聽埠
'daemonize' => true,
'app_path' => '/home/www/tp/application/',
基本操作
如果要停止服務,可以使用
php think swoole stop
reload
服務
php think swoole reload
stop
服務
php think swoole stop
restart
服務
php think swoole restart
restart
和reload
的區別是,restart
會先stop
然後start
,而reload
則是平滑重啟服務,不會中斷服務。
如果你需要修改地址和埠,可以修改swoole.php
配置檔案
'host' => 'tp5.com', // 監聽地址
'port' => 8080, // 監聽埠
改完後,需要重啟服務才能生效
php think swoole restart
現在可以直接訪問
http://tp5.com:8080
如果你需要設定
80
埠,需要root
許可權才可以。
如果你安裝的是
2.0.12+
版本的擴充套件,還可以支援在命令列指定地址和埠,例如:
php think swoole -H tp.com -p 9508
如果啟動了多個不同埠的服務,reload
、restart
和stop
操作必須也是針對某個埠的才能正確操作,我們以reload
操作為例進行說明。
如果我們需要reload
前面啟動的tp.com:9508
服務,下面的指令是錯誤的
php think swoole reload
可能會出現錯誤提示:
no swoole http server process running.
必須帶上正確的埠號(host
不是必須的)
php think swoole reload -p 9508
然後,你會看到提示資訊如下,表示reload
成功:
Reloading swoole http server...
> success
Cookie
和Session
由於Swoole
的特殊性,擴充套件本身接管了Cookie
類和Session
類的處理,因此不要呼叫(包括依賴注入)think\Cookie
和think\Session
類,而應該改為think\swoole\Cookie
類和think\swoole\Session
類。但think\facade\Cookie
和think\facade\Session
類的用法是正常的,因此原來的靜態方法呼叫依然可以正常使用。同時,Request
物件的cookie
方法和session
方法也可以正常使用。
關於Swoole
的Session
的用法,這裡要特別強調下。
Swoole
是沒有Session
的概念,因此所有PHP內建的session
函式都是無效的,think-swoole
擴充套件單獨封裝了一個Session
類,和系統的Session
機制無關。
該擴充套件提供的think\swoole\Session
類是基於swoole_table
和ThinkPHP
快取的混合解決方案。
每次Session::start()
的時候系統會從swoole_table
或者定義的快取型別中獲取當前使用者的Session
資料,而session_id
資料則通過Cookie
獲取。並且在當前worker
程序中不會過期,但每次從swoole_table
或者快取中獲取session
的時候則會判斷是否過期,session
的有效期還是通過session.php
配置檔案的expire
配置引數進行設定。
swoole_table
一個基於共享記憶體和鎖實現的超高效能,併發資料結構。用於解決多程序/多執行緒資料共享和同步加鎖問題。
由於swoole_table
需要事先分配記憶體大小和欄位定義,在swoole.php
配置檔案中需要新增定義:
'table' => [
// 定義最大記錄數
'size' => 1024,
// 欄位型別定義(目前僅支援 string int 和 float型別)
'column' =>[
'data' => ['string',255], // 字串型別 長度為255個位元組
'expire'=> ['int',8], // 整型 長度為8
],
],
swoole_table
分配的記憶體無法動態擴容和調整欄位型別,如果修改則需要重啟才能生效。
然後在session.php
配置檔案中,新增
'use_swoole_table' => true,
swoole_table
是一個可選方案。我們更建議使用快取機制來處理Session
,如果你的應用比較大,則應該配置使用redis
之類的快取機制更加適合,直接在你的cache.php
中定義相關快取配置即可。
為了避免複雜,swoole的
Session
類不再支援prefix
引數,如果需要區分比如前後臺不同session
的需求,可以使用name
引數進行區分。
檔案監控
由於Swoole
服務執行過程中PHP檔案是常駐記憶體執行的,這樣可以避免重複讀取磁碟、重複解釋編譯PHP,以便達到最高效能。所以更改業務程式碼後必須手動reload
或者restart
才能生效。
think-swoole
擴充套件提供了監控檔案更新的功能,在檢測到相關目錄的檔案有更新後會自動reload
,從而不需要手動進行reload
操作,方便開發除錯。
如果你的應用開啟了除錯模式,檔案監控功能是自動開啟的。原則上,在部署模式下不建議開啟檔案監控,一方面有效能損耗,另外一方面對檔案所做的任何修改都需要確認無誤才能進行更新部署。如果你確實需要在部署模式下開啟檔案監控,可以設定如下:
'file_monitor' => true, // 開啟檔案監控
'file_monitor_interval' => 1, // 檔案監控檢測的時間間隔
'file_monitor_path' => '', // 檔案監控目錄 一般不需要設定 預設會監控應用目錄和配置目錄
事件回撥
擴充套件自帶的HTTPServer
包含了onWorkerStart
和onRequest
兩個事件回撥,你如果需要增加其它的回撥事件處理,可以在配置檔案中直接新增:
'WorkerStop' => function($server, $worker_id) {
},
'WorkerError' => function($serv, $worker_id, $worker_pid, $exit_code, $signal) {
},
關於事件回撥的具體用法,可以參考swoole
官方文件。
如果不熟悉內部機制,請勿隨意替換和更改
onWorkerStart
和onRequest
事件回撥,會導致不可預期的結果。
Nginx+Swoole
部署
可以使用Nginx
請求轉發到Swoole
的方式部署,充分發揮Nginx
的配置優勢和強大功能。
server {
listen 80;
root /var/www/tp/public/;
server_name 127.0.0.1;
index index.html index.htm index.php;
location / {
proxy_http_version 1.1;
proxy_set_header Connection "keep-alive";
proxy_set_header X-Real-IP $remote_addr;
proxy_pass http://127.0.0.1:9501;
}
}
靜態資源訪問
如果你沒有使用Nginx
代理的話,為了確保靜態資源的正常訪問,請確認下面的引數配置正確:
// 網站根目錄位置
'document_root' => Env::get('root_path') . 'public',
// 開啟靜態資源處理
'enable_static_handler' => true,
使用Chrome瀏覽器會自動請求一次
favicon.ico
,所以確保你的網站根目錄下面有存在favicon.ico
檔案,否則會產生一次404
請求的錯誤日誌。
HTTPS
和HTTP2
支援
如果需要配置你的HTTP
服務支援HTTPS
,需要增加配置如下:
'ssl' => true,
'ssl_cert_file' => __DIR__.'/ssl.crt',
'ssl_key_file' => __DIR__.'/ssl.key',
記得準確指定你的cert
證書和key
私鑰的路徑。
使用
SSL
必須在編譯swoole
時加入--enable-openssl
選項
如果需要支援HTTP2
協議,則在SSL支援的基礎上還需要在編譯的時候加入--enable-http2
選項
./configure --enable-openssl --enable-http2
然後在swoole.php
中增加配置
'open_http2_protocol' => true
其它注意事項
為了讓你的應用能夠順利的執行在
Swoole
上面,擴充套件做了大量的底層處理工作,包括讓你的請求資料、Cookie
和Session
正常運作。
在
Swoole
下面,不能使用$_GET
、$_POST
、$_REQUEST
、$_SERVER
、$_COOKIE
以及$_SESSION
等原生的PHP用法,只能使用框架提供的類和方法進行獲取。
錯誤的用法:
$name = $_GET['name'];
$name = $_POST['name'];
$name = $_COOKIE['name'];
$name = $_SESSION['name'];
$host = $_SERVER['HTTP_HOST'];
V2.0.11+
版本開始,系統可以支援原生全域性變數的獲取,但仍然不建議使用。
正確的用法(以下用法都採用了Facade
靜態代理類):
$name = Request::get('name');
$name = Request::param('name');
$name = Cookie::get('name');
$name = Session::get('name');
$host = Request::server('http_host');
如果你要獲取php://input
內容,必須把原來的程式碼
file_get_contents('php://input');
改成
Request::getInput();
不過更建議使用
Request::put();
因為可以支援json
資料的自動解析而不需要手動進行json_decode
。
由於onWorkerStart
執行的時候還沒有HTTP_HOST
,因此最好在應用配置檔案config/app.php
中設定app_host
。
請不要呼叫PHP原生的header
方法,使用Response
物件的header
方法替代。
不要使用PHP原生的session
相關函式,使用Session
類的相關方法。
目前為止,尚有一些功能不夠完善(例如檔案上傳之類),請期待後續版本更新。
快速啟動Swoole Server
現在來看第二個場景,通過簡單的配置快速啟動一個swoole
服務,包括WebSocket
/Http
/Socket
服務。
可以支援直接啟動一個Swoole server(需要think-swoole
擴充套件 2.0.9+
版本)
php think swoole:server
會顯示如下資訊:
Starting swoole server...
Swoole socket server started: <0.0.0.0:9508>
You can exit with `CTRL-C`
這個時候已經在0.0.0.0:9508
啟動一個Websocket
服務。
你可以在瀏覽器中訪問
http://127.0.0.1:9508
會看到類似下面的頁面(後面是一串隨機數)。
守護程序
如果需要使用守護程序方式執行,可以使用
php think swoole:server -d
或者在swoole.php
檔案中設定
'daemonize' => true
配置檔案
如果需要自定義引數,可以在config/swoole_server.php
中進行配置,包括:
配置引數 | 描述 | 預設值 |
---|---|---|
type | 服務型別(支援socket、http或者留空) | socket |
host | 監聽地址 | 0.0.0.0 |
port | 監聽埠 | 9508 |
mode | 執行模式 | SWOOLE_PROCESS |
sock_type | Socket type | SWOOLE_SOCK_TCP |
daemonize | 守護程序 | false |
注意不要和
swoole.php
檔案檔案混淆,兩者的作用完全不同。
並且支援swoole
所有的引數,以及支援使用閉包方式定義相關事件回撥。
return [
// 擴充套件自身配置
'host' => '0.0.0.0', // 監聽地址
'port' => 9501, // 監聽埠
'type' => 'socket', // 服務型別 支援 socket http或者留空
'mode' => SWOOLE_PROCESS,
'sock_type' => SWOOLE_SOCK_TCP,
// 可以支援swoole的所有配置引數
'daemonize' => false,
'worker_num' => 4,
// 事件回撥定義
'onOpen' => function ($server, $request) {
echo "server: handshake success with fd{$request->fd}\n";
},
'onMessage' => function ($server, $frame) {
echo "receive from {$frame->fd}:{$frame->data},opcode:{$frame->opcode},fin:{$frame->finish}\n";
$server->push($frame->fd, "this is server");
},
'onRequest' => function ($request, $response) {
$response->end("<h1>Hello Swoole. #" . rand(1000, 9999) . "</h1>");
},
'onClose' => function ($ser, $fd) {
echo "client {$fd} closed\n";
},
];
自定義服務類
如果你需要更高階的自定義事件回撥,也可以使用自定義的Swoole
服務類。
<?php
namespace app\http;
use think\swoole\Server;
class Swoole extends Server
{
protected $host = '127.0.0.1';
protected $port = 9502;
protected $serverType = 'socket';
protected $mode = SWOOLE_PROCESS;
protected $sockType = SWOOLE_SOCK_TCP;
protected $option = [
'worker_num'=> 4,
'daemonize' => true,
'backlog' => 128
];
public function onReceive($server, $fd, $from_id, $data)
{
$server->send($fd, 'Swoole: '.$data);
}
}
自定義服務類必須繼承
think\swoole\Server
類,支援swoole
所有的回撥方法定義(回撥方法必須是public
型別)。
serverType
屬性定義為 socket
或者http
則支援swoole的swoole_websocket_server
和swoole_http_server
然後在swoole_server.php
中增加配置引數:
return [
'swoole_class' => 'app\http\Swoole',
];
定義該引數後,其它配置引數均不再有效。
然後就可以在命令列啟動服務端
php think swoole:server
一樣可以支援使用守護程序模式執行,
php think swoole:server -d
同樣也支援reload
、restart
和stop
操作。
php think swoole:server reload
客戶端程式碼的實現有很多,如果你是使用PHP的話,可以用Swoole\Client
類。
<?php
namespace app\index\controller;
use Swoole\Client;
use think\Controller;
class Test extends Controller
{
public function index() {
$client = new Client(SWOOLE_SOCK_TCP, SWOOLE_SOCK_SYNC);
$ret = $client->connect("127.0.0.1", 9501);
if(empty($ret)){
echo 'error!connect to swoole_server failed';
} else {
$client->send('test');
}
}
}
啟動多個swoole
服務
你可以通過命令列的指令啟動多個不同埠的swoole
服務,例如:
php think swoole:server -p 9800
php think swoole:server -p 9700
如果要分別對不同埠的服務進行stop
操作,務必使用
php think swoole:server stop -p 9800
php think swoole:server stop -p 9700