# 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)),进程模型示意图如下:
![进程模型](../images/swoole_process.png "进程模型")
- 它是一个多进程模型框架,启动时创建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进程
### 执行流程
![执行流程](../images/swoole执行流程.png "执行流程")
### 异步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 附录