## **Swoole概述**
[Swoole](https://www.swoole.com/)是面向生產環境的PHP異步網絡通信引擎,使用純C語言編寫(Swoole 4 開始逐漸改為通過 C++ 編寫),提供了PHP語言的異步多線程服務器、異步TCP/UDP網絡客戶端、異步MySQL、異步Redis、數據連接池、AsyncTask、消息隊列、毫秒定時器、異步文件讀寫、異步DNS查詢。除了異步IO的支持外,Swoole還為PHP多進程的模式設計了多個并發數據結構和IPC通信機制,可以大大簡化多進程并發編程的工作。
之前PHP一直被詬病的一個原因就是它是同步阻塞式語言,這在Web應用這種IO密集型領域,對于編寫高并發高性能的應用是一個重大阻礙。有了[Swoole]([https://wiki.swoole.com](https://wiki.swoole.com/))之后,PHP開發人員可以輕松編寫高性能的異步并發TCP、UDP、Unix Socket、HTTP以及WebSocket服務,從而使得PHP語言在異步IO和網絡通信領域開疆拓土。
## **安裝啟用**
Swoole是PHP的一個擴展,可以通過PHP擴展的方式進行安裝和啟用(不同于普通的擴展只是提供一個庫函數,`Swoole`擴展在運行后會接管`PHP`的控制權,進入事件循環,當`IO`事件發生后底層會自動回調指定的`PHP`函數)。
如果是在服務器安裝的話,以Ubuntu系統為例,通過執行下列命令安裝即可:
```
pecl install swoole
```
然后通過`php -i | grep php.ini`定位`php.ini`文件所在位置,并打開該配置文件,在文件末尾追加如下內容:
~~~
[swoole]
extension=swoole.so
~~~
保存并退出,在終端運行`php -m`,如果看到擴展里包含`swoole`,說明安裝啟用成功。
## **測試Swoole**
下面我們基于Swoole編寫兩個簡單的功能來測試Swoole是否可以正常工作。
### **HTTP 服務器**
首先我們通過Swoole編寫一個簡單的HTTP服務器,在測試目錄下創建一個`http_server.php`文件,編寫文件代碼如下:
```
<?php
// 表明服務器啟動后監聽本地 9051 端口
$server = new swoole_http_server('127.0.0.1', 9501);
// 服務器啟動時返回響應
$server->on("start", function ($server) {
echo "Swoole http server is started at http://127.0.0.1:9501\n";
});
// 向服務器發送請求時返回響應
// 可以獲取請求參數,也可以設置響應頭和響應內容
$server->on("request", function ($request, $response) {
$response->header("Content-Type", "text/plain");
$response->end("Hello World\n");
});
// 啟動 HTTP 服務器
$server->start();
```
這樣,一個最基本的 HTTP 服務器就完成了,其工作原理和工業級的 Apache 和 Nginx 服務器類似,只不過提供的是最簡單的服務器監聽和響應功能罷了,我們在終端啟用這個服務器:

這樣,表示服務器已經啟動并且在監聽請求了,到瀏覽器中訪問`http://127.0.0.1:9501`,即可獲取服務器輸出響應內容:

### **TCP服務器和客戶端**
接下來,我們通過Swoole及其協程特性實現一個簡單的TCP服務器和客戶端(TCP 協議需要雙方通過三次握手建立連接后才能進行通信),我們還是在前面的測試目錄下創建一個`tcp_server.php`文件用于編寫 TCP 服務端代碼:
```
<?php
namespace Swoole;
// 監聽本地 9503 端口,等待客戶端請求
$server = new Server("127.0.0.1", 9503);
// 建立連接時輸出
$server->on('connect', function ($serv, $fd){
echo "Client:Connect.\n";
});
// 接收消息時返回內容
$server->on('receive', function ($serv, $fd, $from_id, $data) {
$serv->send($fd, 'Swoole: '.$data);
$serv->close($fd);
});
// 連接關閉時輸出
$server->on('close', function ($serv, $fd) {
echo "Client: Close.\n";
});
// 啟動 TCP 服務器
$server->start();
```
然后在該目錄下創建一個`tcp_client.php`文件用于編寫 TCP 客戶端代碼:
```
<?php
namespace Swoole;
// Swoole4以后通過協程來實現異步通信
go(function () {
$client = new Coroutine\Client(SWOOLE_SOCK_TCP);
// 嘗試與指定 TCP 服務端建立連接(IP和端口號需要與服務端保持一致,超時時間為0.5秒)
if ($client->connect("127.0.0.1", 9503, 0.5)) {
// 建立連接后發送內容
$client->send("hello world\n");
// 打印接收到的消息
echo $client->recv();
// 關閉連接
$client->close();
} else {
echo "connect failed.";
}
});
```
這樣,一個最基本的 TCP 服務端和客戶端程序就編寫完成了,在終端先啟動 TCP 服務端:
~~~
php tcp_server.php
~~~
然后新開啟一個終端窗口,啟動 TCP 客戶端,可以看到輸出從 TCP 服務端接收到消息后 TCP 客戶端退出,此時服務端也會打印連接建立和斷開的日志消息:

客戶端退出后,服務端依然處理監聽狀態,等待下一個請求。
>注:進程是應用程序的啟動實例,擁有代碼和打開的文件資源,數據資源,獨立的內存空間;
線程是程序的執行者,一個進程至少包含一個主線程,也可有更多的子線程,線程有分時調度,搶占式調度兩種調度策略;
協程是輕量級線程,它的創建、切換、掛起、銷毀全為內存操作,消耗非常低。協程在線程里執行,由用戶手動切換調度【用戶空間線程】,其調度策略是協作式調度。目前Swoole4僅有部分事件回調函數底層自動創建了協程,以下回調函數可以調用協程客戶端,可以查看這里https://wiki.swoole.com/wiki/page/696.html;