1. 程式人生 > >ThinkPHP 5.1 Swoole 快速上手指南

ThinkPHP 5.1 Swoole 快速上手指南

本篇內容主要講述了最新的think-swoole擴充套件的使用。

本指南的目的不是為了讓你掌握Swoole開發,而且幫助你使用think-swoole快速部署ThinkPHP5.1應用到SwooleHttpServer,以及使用快速啟動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

restartreload的區別是,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

如果啟動了多個不同埠的服務,reloadrestartstop操作必須也是針對某個埠的才能正確操作,我們以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

CookieSession

由於Swoole的特殊性,擴充套件本身接管了Cookie類和Session類的處理,因此不要呼叫(包括依賴注入)think\Cookiethink\Session類,而應該改為think\swoole\Cookie類和think\swoole\Session類。但think\facade\Cookiethink\facade\Session類的用法是正常的,因此原來的靜態方法呼叫依然可以正常使用。同時,Request物件的cookie方法和session方法也可以正常使用。

關於SwooleSession的用法,這裡要特別強調下。

Swoole是沒有Session的概念,因此所有PHP內建的session函式都是無效的,think-swoole擴充套件單獨封裝了一個Session類,和系統的Session機制無關。

該擴充套件提供的think\swoole\Session類是基於swoole_tableThinkPHP快取的混合解決方案。

每次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包含了onWorkerStartonRequest兩個事件回撥,你如果需要增加其它的回撥事件處理,可以在配置檔案中直接新增:

'WorkerStop'	=>	function($server, $worker_id) {

},
'WorkerError'	=>	function($serv, $worker_id, $worker_pid, $exit_code, $signal) {

},

關於事件回撥的具體用法,可以參考swoole官方文件。

如果不熟悉內部機制,請勿隨意替換和更改onWorkerStartonRequest事件回撥,會導致不可預期的結果。

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請求的錯誤日誌。

HTTPSHTTP2支援

如果需要配置你的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上面,擴充套件做了大量的底層處理工作,包括讓你的請求資料、CookieSession正常運作。

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_serverswoole_http_server

然後在swoole_server.php中增加配置引數:

return [
	'swoole_class'	=>	'app\http\Swoole',
];

定義該引數後,其它配置引數均不再有效。

然後就可以在命令列啟動服務端

php think swoole:server

一樣可以支援使用守護程序模式執行,

php think swoole:server -d

同樣也支援reloadrestartstop 操作。

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