# 2.2 swoole
## 簡介
PHP的異步、并行、高性能網絡通信引擎,使用純C語言編寫,提供了PHP語言的異步多線程服務器,異步TCP/UDP網絡客戶端,異步MySQL,異步Redis,數據庫連接池,AsyncTask,消息隊列,毫秒定時器,異步文件讀寫,異步DNS查詢。 Swoole內置了Http/WebSocket服務器端/客戶端、Http2.0服務器端。
## 官網
[https://www.swoole.com](https://www.swoole.com)
## php-msf使用的swoole特性
我們在學習msf之前應該先了解swoole的各種特性,swoole的功能很多,各種使用姿勢,本節主要介紹msf框架所使用的swoole主要特性。
### 進程模型
msf框架使用了swoole的進程模式([更多模式的介紹](https://wiki.swoole.com/wiki/page/353.html)),進程模型示意圖如下:

- 它是一個多進程模型框架,啟動時創建2 + n + m個進程;
- 2=1個master進程+1個manager進程
- master進程是Server實例的主進程,負責fork Manager進程及accept用戶連接
- manager進程為管理進程,負責創建和管理所有的Worker和TaskWorker進程
- Reactor線程運行在master進程,實際運行epoll實例,用于accept客戶端連接以及接收客戶端數據
- Worker進程接受Reactor線程分配的用戶請求,處理數據后返回給Reactor線程
- TaskWorker進程接受Worker投遞的耗時任務,處理完成后執行異步回調函數,通知Worker進程
### 執行流程

### 異步DNS
由于在發起http請求時,通常情況下URL中包含域名,而域名解析是一次UDP的網絡請求,通過gethostbyname()函數進行域名解析是同步阻塞的,這與msf研發目標是相違背的,故我們需要異步查詢DNS,swoole內置一個純異步IO實現的異步DNS客戶端:
```php
swoole_async_dns_lookup("www.baidu.com", function($host, $ip){
echo "{$host} : {$ip}\n";
});
```
[更多介紹](https://wiki.swoole.com/wiki/page/186.html)
### 異步Http Client
傳統的curl請求是同步阻塞的,不能滿足構建純異步的Server需求,swoole內置異步的http client:
```php
Swoole\Async::dnsLookup("www.baidu.com", function ($domainName, $ip) {
$cli = new swoole_http_client($ip, 80);
$cli->setHeaders([
'Host' => $domainName,
"User-Agent" => 'Chrome/49.0.2587.3',
'Accept' => 'text/html,application/xhtml+xml,application/xml',
'Accept-Encoding' => 'gzip',
]);
$cli->get('/index.html', function ($cli) {
echo "Length: " . strlen($cli->body) . "\n";
echo $cli->body;
});
});
```
[更多介紹](https://wiki.swoole.com/wiki/page/670.html)
### 異步Redis Client
我們常用的phpredis也是同步阻塞的,不能滿足構建純異步的Server需求,swoole內置異步的redis client:
```php
$client = new swoole_redis;
$client->connect('127.0.0.1', 6379, function (swoole_redis $client, $result) {
if ($result === false) {
echo "connect to redis server failed.\n"
return;
}
$client->set('key', 'swoole', function (swoole_redis $client, $result) {
var_dump($result);
});
});
```
[更多介紹](https://wiki.swoole.com/wiki/page/522.html)
### 異步MySQL Client
我們常用的pdo_mysql/mysqli,不能滿足構建純異步的Server需求,swoole內置異步的mysql client:
```php
$db = new swoole_mysql;
$server = array(
'host' => '192.168.56.102',
'port' => 3306,
'user' => 'test',
'password' => 'test',
'database' => 'test',
'charset' => 'utf8', //指定字符集
'timeout' => 2, // 可選:連接超時時間(非查詢超時時間),默認為SW_MYSQL_CONNECT_TIMEOUT(1.0)
);
$db->connect($server, function ($db, $r) {
if ($r === false) {
var_dump($db->connect_errno, $db->connect_error);
die;
}
$sql = 'show tables';
$db->query($sql, function(swoole_mysql $db, $r) {
if ($r === false)
{
var_dump($db->error, $db->errno);
}
elseif ($r === true )
{
var_dump($db->affected_rows, $db->insert_id);
}
var_dump($r);
$db->close();
});
});
```
[更多介紹](https://wiki.swoole.com/wiki/page/517.html)
### Http Server
我們只需要簡單的幾行代碼就能構建一個健壯的Http Server,因為swoole-1.7.7增加了內置Http服務器的支持,通過幾行代碼即可寫出一個異步非阻塞多進程的Http服務器。
```php
$http = new swoole_http_server("127.0.0.1", 9501);
$http->on('request', function ($request, $response) {
$response->end("<h1>Hello Swoole. #".rand(1000, 9999)."</h1>");
});
$http->start()
```
[更多介紹](https://wiki.swoole.com/wiki/page/326.html)
### 異步毫秒定時器
msf框架內部的功能實現有基于異步毫秒定時器,比如協程調度,請求超時等等。
[更多介紹](https://wiki.swoole.com/wiki/page/244.html)
### 異步文件系統IO
msf框架寫日志是純異步的IO,也就是說請求結束后,不需要等待日志寫入成功就可以處理下一個請求。
[更多介紹](https://wiki.swoole.com/wiki/page/183.html)
### 進程管理
在swoole的進程模式下,我們還可以創建自定義的進程,比如msf框架在server啟動時會創建config進程,用于全局配置創建與更新,同時收集server的所有worker運行狀態。
[更多介紹](https://wiki.swoole.com/wiki/page/p-process.html)
- 0 文檔說明
- 1 為什么研發新框架
- 1.1 傳統php-fpm工作模式的問題
- 1.2 壓測數據對比
- 1.3 小結
- 2 微服務框架研發概覽
- 2.1 通信框架技術選型
- 2.2 swoole
- 2.3 協程原理
- 2.4 異步、并發
- 2.5 小結
- 3 框架運行環境
- 3.1 環境變量
- 3.2 運行代碼
- 3.3 docker
- 3.4 小結
- 4 框架結構
- 4.1 結構概述
- 4.2 控制器
- 4.3 模型
- 4.4 視圖
- 4.5 同步任務
- 4.6 配置
- 4.7 路由
- 4.8 小結
- 5 框架組件
- 5.1 協程
- 5.2 類的加載
- 5.3 異步Http Client
- 5.4 請求上下文
- 5.5 連接池
- 5.6 對象池
- 5.7 RPC
- 5.8 公共庫
- 5.9 RESTful
- 5.10 多語言
- 5.11 雜項
- 5.12 小結
- 6 常見問題
- 7 附錄