[Swoole] 在Ubuntu下安裝、快速開始
- 2019 年 10 月 13 日
- 筆記
本文主要講述在 Ubuntu 下編譯安裝 Swoole,並根據官方文檔給出的demo進行了測試和搬運,包括:TCP伺服器、UDP伺服器、HTTP伺服器、WebSocket伺服器、非同步客戶端、定時器和協程相關,通過模仿官方例子領略Swoole給PHPer帶來全新的編程模式和思想。
它彌補PHP在網路編程的不足。
一、說明
運行環境:
win10
下的Ubuntu
、PHP7.2
、Swoole4.3
二、安裝Swoole
- 下載解壓
sudo wget https://github.com/swoole/swoole-src/archive/v4.3.6.tar.gz cp v4.3.6.tar.gz swoole-v4.3.6.tar.gz tar -zxvf swoole-v4.3.6.tar.gz cd swoole-v4.3.6
- 安裝依賴
# 根據下面的編譯提示進行選擇安裝 sudo apt-get install php-dev sudo apt-get install autoconf
- 編譯安裝
# 根據自己 php 安裝的目錄 cd swoole-v4.3.6 /usr/local/php/bin/phpize ./configure make sudo make install
make
的結果:
... ---------------------------------------------------------------------- Libraries have been installed in: /home/fly/swoole-src-4.3.6/modules If you ever happen to want to link against installed libraries in a given directory, LIBDIR, you must either use libtool, and specify the full pathname of the library, or use the `-LLIBDIR' flag during linking and do at least one of the following: - add LIBDIR to the `LD_LIBRARY_PATH' environment variable during execution - add LIBDIR to the `LD_RUN_PATH' environment variable during linking - use the `-Wl,--rpath -Wl,LIBDIR' linker flag - have your system administrator add LIBDIR to `/etc/ld.so.conf' See any operating system documentation about shared libraries for more information, such as the ld(1) and ld.so(8) manual pages. ---------------------------------------------------------------------- Build complete. Don't forget to run 'make test'.
sudo make install
的結果:
Installing shared extensions: /usr/local/php/lib/php/extensions/no-debug-non-zts-20170718/ Installing header files: /usr/local/php/include/php/
- 配置 php.ini
# 編譯安裝成功後,在 php.ini 文件加入 extension=swoole.so # extension=/usr/lib/php/20170718/swoole.so
查看是否載入 swoole
擴展
php -m
- 錯誤排查(可忽略)
下面錯誤很明顯,需要指定 php-conf
路徑:
configure: error: Cannot find php-config. Please use –with-php-config=PATH
解決方法:
./configure –with-php-config=/usr/local/php/bin/php-config
三、快速入門
a) TCP 伺服器
# 創建 php 文件 vi tcp_server.php
<?php //創建Server對象,監聽 127.0.0.1:9501埠 $serv = new SwooleServer("127.0.0.1", 9501); //監聽連接進入事件 $serv->on('Connect', function ($serv, $fd) { echo "Client: Connect.n"; }); //監聽數據接收事件 $serv->on('Receive', function ($serv, $fd, $from_id, $data) { $serv->send($fd, "Server: ".$data); }); //監聽連接關閉事件 $serv->on('Close', function ($serv, $fd) { echo "Client: Close.n"; }); //啟動伺服器 $serv->start();
# 程式運行測試 # 運行 server php tcp_server.php # 使用telnet 測試(退出telnet:Ctrl+] 回車,輸入quit 回車) telnet 127.0.0.1 9501
b) UDP 伺服器
vi udp_server.php
<?php //創建Server對象,監聽 127.0.0.1:9502埠,類型為SWOOLE_SOCK_UDP $serv = new swoole_server("127.0.0.1", 9502, SWOOLE_PROCESS, SWOOLE_SOCK_UDP); //監聽數據接收事件 $serv->on('Packet', function ($serv, $data, $clientInfo) { $serv->sendto($clientInfo['address'], $clientInfo['port'], "Server ".$data); var_dump($clientInfo); }); //啟動伺服器 $serv->start();
# 運行 php udp_server.php # 使用 netcat 連接 netcat -u 127.0.0.1 9502
c) HTTP 伺服器
vi http_server.php
<?php $http = new SwooleHttpServer("0.0.0.0", 9501); $http->on('request', function ($request, $response) { if ($request->server['path_info'] == '/favicon.ico' || $request->server['request_uri'] == '/favicon.ico') { return $response->end(); } var_dump($request->get, $request->post); $response->header("Content-Type", "text/html; charset=utf-8"); $response->end("<h1>Hello Swoole. #".rand(1000, 9999)."</h1>"); }); $http->start();
# 程式運行測試 php http_server.php # 瀏覽器訪問 127.0.0.1:9501
d) WebSocket 伺服器
WebSocket伺服器是建立在Http伺服器之上的長連接伺服器,客戶端首先會發送一個Http的請求與伺服器進行握手。握手成功後會觸發onOpen事件,表示連接已就緒,onOpen函數中可以得到$request對象,包含了Http握手的相關資訊,如GET參數、Cookie、Http頭資訊等。
建立連接後客戶端與伺服器端就可以雙向通訊了。
vi ws_server.php
<?php //創建websocket伺服器對象,監聽0.0.0.0:9502埠 $ws = new swoole_websocket_server("0.0.0.0", 9502); //監聽WebSocket連接打開事件 $ws->on('open', function ($ws, $request) { var_dump($request->fd, $request->get, $request->server); $ws->push($request->fd, "hello, welcomen"); }); //監聽WebSocket消息事件 $ws->on('message', function ($ws, $frame) { echo "Message: {$frame->data}n"; $ws->push($frame->fd, "server: {$frame->data}"); }); //監聽WebSocket連接關閉事件 $ws->on('close', function ($ws, $fd) { echo "client-{$fd} is closedn"; }); $ws->start();
# 程式運行 php ws_server.php
//使用瀏覽器JS程式碼如下 var wsServer = 'ws://127.0.0.1:9502'; var websocket = new WebSocket(wsServer); websocket.onopen = function (evt) { console.log("Connected to WebSocket server."); }; 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); };
e) 定時器
swoole提供了類似JavaScript的setInterval/setTimeout非同步高精度定時器,粒度為毫秒級。
vi timer_tick.php
//每隔2000ms觸發一次 $timerId = swoole_timer_tick(2000, function ($timer_id) { echo "tick-2000msn"; }); //9000ms後執行此函數 swoole_timer_after(9000, function () use ($timerId) { echo "after-9000ms.n"; //清除定時器 swoole_timer_clear($timerId); });
php timer_tick.php
f) 同步、非同步 TCP 客戶端
vi tcp_client.php
<?php $client = new swoole_client(SWOOLE_SOCK_TCP); //連接到伺服器 if (!$client->connect('127.0.0.1', 9501, 0.5)) { die("connect failed."); } //向伺服器發送數據 if (!$client->send("hello world")) { die("send failed."); } //從伺服器接收數據 $data = $client->recv(); if (!$data) { die("recv failed."); } echo $data; //關閉連接 $client->close();
# 非同步只能用於cli vi tcp_async_client.php
<?php $client = new swoole_client(SWOOLE_SOCK_TCP, SWOOLE_SOCK_ASYNC); //註冊連接成功回調 $client->on("connect", function($cli) { $cli->send("hello worldn"); }); //註冊數據接收回調 $client->on("receive", function($cli, $data){ echo "Received: ".$data."n"; }); //註冊連接失敗回調 $client->on("error", function($cli){ echo "Connect failedn"; }); //註冊連接關閉回調 $client->on("close", function($cli){ echo "Connection closen"; }); //發起連接 $client->connect('127.0.0.1', 9501, 0.5);
g) 協程客戶端
vi xxx.php
<?php $http = new swoole_http_server("0.0.0.0", 9501); $http->on('request', function ($request, $response) { $db = new SwooleCoroutineMySQL(); $db->connect([ 'host' => '127.0.0.1', 'port' => 3306, 'user' => 'user', 'password' => 'pass', 'database' => 'test', ]); $data = $db->query('select * from test_table'); $response->end(json_encode($data)); }); $http->start();
h) 協程:並發 shell_exec
vi xxx.php
<?php $c = 10; while($c--) { go(function () { //這裡使用 sleep 5 來模擬一個很長的命令 co::exec("sleep 5"); }); }