­

[Swoole] 在Ubuntu下安裝、快速開始

  • 2019 年 10 月 13 日
  • 筆記

本文主要講述在 Ubuntu 下編譯安裝 Swoole,並根據官方文檔給出的demo進行了測試和搬運,包括:TCP伺服器、UDP伺服器、HTTP伺服器、WebSocket伺服器、非同步客戶端、定時器和協程相關,通過模仿官方例子領略Swoole給PHPer帶來全新的編程模式和思想。

它彌補PHP在網路編程的不足。

一、說明

運行環境:win10 下的 UbuntuPHP7.2Swoole4.3

參考文檔: https://wiki.swoole.com/wiki/page/p-quickstart.html

二、安裝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 測試(退出telnetCtrl+] 回車,輸入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");          });      }

i) 協程:Go + Chan + Defer

參考官方文檔:
https://wiki.swoole.com/wiki/page/p-csp.html