Swoole 是什么

Swoole 是一个为 PHP 用 C 和 C++ 编写的基于事件的高性能异步&协程并行网络通信引擎

image-20200721170433437

同步

1
2
$data = file_get_contents('./data.json');
echo $data;

这个是常见的文件读取操作,在 file_get_contents 函数从磁盘上拿回文件数据前,代码不会继续运行,而是等待返回,因为后续的打印数据依赖上一条指令的返回值,这就是常见的同步编程

异步

Jqury 的 ajax

1
2
3
4
5
6
7
8
9
10
11
12
13
14
$.ajax({
url: "foo",
data: 1,
success: function(e){
$.ajax({
url: "foo",
data: 1,
success: function(b){
console.log(b);
}
})
}
})
console.log('hello')

这段代码在运行到 ajax 的时候,函数会直接返回,马上就可以看到打印出来的 hello

这就是异步,不会遇到 IO 阻塞,但是它也带来了新的问题,当运行到 hello 的时候,我们必须等待 ajax 的回调被触发,然后看到打印出相应的数据。它的执行不是单行顺序的,而是嵌套的

当业务需求越来越复杂的时候,这样的嵌套可读性极差

Swoole 可以做什么

异步多线程协程服务器及客户端

异步 MySQL、Redis、数据库连接池、任务队列

HTTP、websocket 服务器/客户端

异步文件读写

部署 php-swoole

官网:https://www.swoole.com/

安装方式参考官网,这里使用 docker 部署安装

docker 官方镜像:https://hub.docker.com/r/phpswoole/swoole

1
2
3
4
5
6
7
8
9
docker pull phpswoole/swoole

# 使用 docker images 查看镜像
[root@localhost ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
phpswoole/swoole latest 8a3042f8a956 5 weeks ago 471MB
php 7.4-fpm 5b23307ceb6e 5 weeks ago 405MB
nginx latest 2622e6cca7eb 6 weeks ago 132MB
php 7.0-fpm 29e9a8718c7b 19 months ago 357MB

启动 swoole 容器

image-20200722103333153

1
2
3
4
5
6
7
8
# 命令详解
docker run -d -p 9501:9501 -v /var/web/swoole:/var/www --name php-swoole --net dev_network phpswoole/swoole

# -d 后台运行
# -p 9501:9501 宿主机9501端口映射swoole容器的9501端口,否则在容器外部是无法通过网络来访问容器内的网络应用和服务的
# -v /var/web/swoole:/var/www 挂在容器数据卷,将宿主机的/var/web/swoole目录挂载到swoole容器的/var/www目录
# --name php-swoole 容器别名命名为 php-swoole
# --net dev_network 自定义的网络 dev_network

测试

在宿主机 /var/web/swoole 目录下新建 server.php

TCP 服务器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//创建Server对象,监听9501端口
$serv = new Swoole\Server("0.0.0.0", 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();

这样就创建了一个 TCP 服务器,监听本机 9501 端口。它的逻辑很简单,当客户端 Socket 通过网络发送一个 hello 字符串时,服务器会回复一个 Server: hello 字符串。

Server 是异步服务器,所以是通过监听事件的方式来编写程序的。当对应的事件发生时底层会主动回调指定的函数。如当有新的 TCP 连接进入时会执行 onConnect 事件回调,当某个连接向服务器发送数据时会回调 onReceive 函数。

  • 服务器可以同时被成千上万个客户端连接,$fd 就是客户端连接的唯一标识符
  • 调用 $server->send() 方法向客户端连接发送数据,参数就是 $fd 客户端标识符
  • 调用 $server->close() 方法可以强制关闭某个客户端连接
  • 客户端可能会主动断开连接,此时会触发 onClose 事件回调

无法连接到服务器的简单检测手段

  • Linux 下,使用 netstat -an | grep 端口,查看端口是否已经被打开处于 Listening 状态
  • 上一步确认后,再检查防火墙问题
  • 注意服务器所使用的 IP 地址,如果是 127.0.0.1 回环地址,则客户端只能使用 127.0.0.1 才能连接上
  • 用的阿里云服务或者腾讯服务,需要在安全权限组进行设置开发的端口