Swoole入门教程(一):服务器开发

Swoole是什么

Swoole 是一个使用 C++ 语言编写的基于异步事件驱动和协程的并行网络通信引擎,为 PHP 提供协程高性能网络编程支持。提供了多种通信协议的网络服务器和客户端模块,可以方便快速的实现 TCP/UDP服务、高性能Web、WebSocket服务、物联网、实时通讯、游戏、微服务等,使 PHP 不再局限于传统的 Web 领域

以上是swoole官网的介绍,这里说下我自己的一些看法。与其他 PHP 扩展(如 Opcache、Imagick、Redis 等)一样,Swoole 也是一个外部扩展,但是Swoole 带来了一些概念。例如,服务器模式原生协程协程调度器多路复用和异步 I/O协程调度器和异步 I/O 状态管理进程管理等。与其他普通php扩展不一样的地方是,Swoole为php开发人员带来的编程方式的改变,让php编程更加Nodejs化,Swoole 为开发者提供使用 PHP 语法方式创建和管理 TCP、HTTP、WebSocket 服务器的手段,与 PHP-FPM 仅支持无状态模型不同,使用 Swoole,您可以在服务器内提供缓存和管理状态以提高性能,达到类型java等静态语言那样常驻内存的效果。它完全提供了一种新的PHP应用程序运行模式
image.png

为什么要使用Swoole

Swoole已经经过了压力测试和验证

国内很多公司都已经用上了swoole了,在招聘网站输入swoole可以看到很多的招聘需求。据统计,swoole已经在高流量的生产环境中经过了压力测试和验证。说明php使用swoole是值得信赖和使用的。

支持多线程

如上所述,Swoole具有多个网络工作者和独立的任务工作者,这使得代码可以延期。长时间运行的进程的延期为你的API和应用程序中许多以前无法实现的方法打开了大门,例如将处理过程推迟到发送响应之后

支持协程

Swoole的Coroutine支持意味着你可以处理大量的请求,即使你正在做大量昂贵的I/O(例如,与你的数据库对话,使用文件系统,进行HTTP请求)。
自举系统只被加载一次,所以你消除了每次请求的15-25%的税。因为它是你初始化的一部分,这意味着你在每次请求中使用的资源更少,包括内存和CPU。对于一些应用程序,这可能意味着你需要更少的服务器,由于异步运行时的存在,这可能已经成为可能。

不需要Server支持,本身就是Server

说到更少的服务器,你不需要网络服务器,因为Swoole就是网络服务器。你可以启动一个只安装PHP的docker容器,你不需要NGINX坐在它的前面。

你不必把NGINX或Apache编在同一个容器中,它可以只是PHP。而且,如果你正在做任何形式的容器化,拥有这些单进程的容器和一种语言是真正的黄金标准。

更多并发请求支持

异步服务器能够处理的请求是非异步服务器的4到7倍,Node已经一次又一次地证明了这点。

安装swoole

通过宝塔安装swoole

这种方式是最简单的方式。直接安装php的swoole插件即可
image.png

通过源码编译安装swoole

此方法同时适用于ubuntu和centos等linux系统

git clone https://github.com/swoole/swoole-src.git
cd swoole-src
phpize
./configure
make && make install

编译安装到系统成功后,需要在 php.ini 中加入一行 extension=swoole.so 来启用 Swoole 扩展

通过docker直接安装启用

docker pull phpswoole/swoole

使用swoole进行服务端编程

Tcp服务器

网络编程中常用Tcp服务器,即使最常见的HTTP1和HTTP2也是基于TCP协议上封装的的,HTTP3才是基于UDP。用Swoole创建服务一般2种方式,异步风格和协程风格,分别对应的Server类是Swoole\Server和Swoole\Coroutine\Server ,
异步风格

$server = new Swoole\Server("127.0.0.1", 9501);
$server->on('connect', function ($server, $fd){
  echo "Client:Connect.\n";
});
$server->on('receive', function ($server, $fd, $reactor_id, $data) {
  $server->send($fd, 'Swoole: '.$data);
  $server->close($fd);
});
$server->on('close', function ($server, $fd) {
  echo "Client: Close.\n";
});
$server->start();

协程风格

协程风格下链接是动态创建和销毁的,可以设置5秒没收到数据自动超时关闭

go(function(){
    $server = new \Swoole\Coroutine\Server('0.0.0.0',9501,false,true);
    $server->handle(function (\Swoole\Coroutine\Server\Connection $conn){
        echo '您好,欢迎进入聊天室'."\n";
        $socket = $conn->exportSocket();
        while (true){
            $data = $conn->recv(5);
            if ($data === '' || $data === false) {
//                $errCode = swoole_last_error();
//                $errMsg = socket_strerror($errCode);
                echo "协程风格下链接是动态创建和销毁的,可以设置5秒没收到数据自动超时关闭\n";
                $conn->close();
                break;
            }
            //发送数据
            $conn->send('您好,您输入的data是: '.$data);
        }
        echo '客户端:'.$socket->fd.'的链接已经关闭';
    });
    $server->start();
});
Swoole\Event::wait();

由于我个人异步风格方式写得比较多,后面就都用协程风格来写。

UDP服务器

Swoole创建Udp服务的类是Swoole\Coroutine\Socket,异步方式请同学自行查看官方文档。

<?php
use function Swoole\Coroutine\go;
go(function (){
    $socket = new Swoole\Coroutine\Socket(AF_INET, SOCK_DGRAM, 0); //domain, type, protocol
    // domain=AF_INET, 使用ipv4通信
    // type=SOCK_DGRAM, 无保障的面向消息的socket,主要用于在网络上发广播信息
    $socket->bind('0.0.0.0', 9501);//绑定监听的ip和端口
    $socket->listen(128);
    $peer = null;
    while (true){
        $data = $socket->recvfrom($peer,5);
        var_dump($data);
        if($peer){
            echo "收到来自{$peer['address']}:{$peer['port']}的消息 : $data\n";
            $socket->sendto($peer['address'], $peer['port'], "你好,你的消息是: $data");
        }
    }
});
Swoole\Event::wait();

HTTP服务器

HTTP服务器对应的类是Swoole\Coroutine\Http\Server,这个就比较常用了,同TCP一样也是通过handle来处理请求,但回调函数置入了Swoole\Http\RequestSwoole\Http\Response 两个对象,这就非常好办了

<?php
use Swoole\Coroutine\Http\Server;
use function Swoole\Coroutine\run;

run(function () {
    $server = new Server('0.0.0.0', 9501, false);
    //可以通过request对象来进一步判断映射路由,
    $server->handle('/', function ($request, $response) {
        $info = $request->header['host'];
        $response->end("<h1>您访问了路径/,来自{$info}</h1>");
    });
    $server->handle('/test', function ($request, $response) {
        $response->end("<h1>您访问了路径/test</h1>");
    });
    $server->handle('/stop', function ($request, $response) use ($server) {
        $response->end("<h1>您访问了路径/stop</h1>");
        $server->shutdown();
    });
    $server->start();
});

image.png

WebSocket服务器

WebSocket同样是采用Swoole\Coroutine\Http\Server,但是处理流程有点不一样。请求进来时必须先调用$response->upgrade();向客户端发送WebSocket握手消息,将请求升级为websocket请求。然后通过while(true)循环处理消息的接收和发送

<?php
use Swoole\WebSocket\CloseFrame;
use function Swoole\Coroutine\go;
go(function (){
    $server = new \Swoole\Coroutine\Http\Server('0.0.0.0',9502,false);
    $server->handle('/',function (\Swoole\Http\Request $request,\Swoole\Http\Response $response){
        $response->upgrade();
        while (true) {
            $frame = $response->recv();
            if ($frame === '') {
                $response->close();
                break;
            } else if ($frame === false) {
                echo '发生错误: ' . swoole_last_error() . "\n";
                $response->close();
                break;
            } else {
                if ($frame->data == 'close' || get_class($frame) === CloseFrame::class) {
                    $response->close();
                    break;
                }
                $response->push("你好 {$request->fd},你说了:{$frame->data}!");
                $response->push("你好啊{$request->fd},我又一次回复 {$frame->data}给你");
            }
        }
        echo '客户端断开了'."\n";
    });
    $server->start();
});
Swoole\Event::wait();

其他服务端

Swoole还可以做很多事情,比如用于物联网的Mqtt服务器,比如用于定时任务处理,还比如消息队列等等,本篇作为开篇先讲到这,后面有时间我会继续输出Swoole相关的知识。

本文基于个人学习心得编写,如有疏漏或错误,还请同学指正。

  • 0
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值