美文网首页
Swoole入门

Swoole入门

作者: jiancaigege | 来源:发表于2018-03-24 13:15 被阅读0次

    简介

    是什么?

    • Swoole是一个PHP扩展,使用纯C语言编写。
    • Swoole内置了Http/WebSocket服务器端/客户端、Http2.0服务器端。
    • Swoole支持AsyncTask,消息队列,毫秒定时器,异步文件读写等功能。
    • Swoole从2.0版本开始支持了内置协程,可以使用完全同步的代码实现异步程序。PHP代码无需额外增加任何关键词,底层自动进行协程调度,实现异步。
    • Swoole可以广泛应用于互联网、移动通信、企业软件、网络游戏、物联网、车联网、智能家庭等领域。

    版本选择

    建议使用的版本:

    • 稳定版:v1.9.23
    • 预览版:v2.0.12

    1.9.x分支已进入特性锁定期,不再开发新功能,仅修复BUG。

    建议使用的PHP版本:

    • PHP5.5或更高版本
    • PHP7.0.13或更高版本

    可以免费使用吗

    Swoole是开源免费的自由软件,授权协议是Apache2.0。企业和个人开发者均可免费使用Swoole的代码,并且在Swoole之上所作的修改可用于商业产品,无需开源(注:必须保留原作者的版权声明)。

    实例讲解

    HttpServer

    swoole内置Http服务器的支持。swoole版的http server相对于php-fpm,最大优势在于高性能:代码一次载入内存,后续无需再解释执行。缺点是调试没有nginx+php-fpm方便。

    使用swoole,通过几行代码即可写出一个异步非阻塞多进程的Http服务器:

    <?php
    $server = new swoole_http_server("0.0.0.0", 9051);
    $server->set([
        'daemonize' => false,//是否后台运行
        'log_file' => 'swoole.log',
    ]);
    
    $server->on('Start', function() {
        swoole_set_process_name("swoole_http_server");
        echo "Start\n";
    });
    
    $server->on('Request', function($request, $response) {
        print_r($request->get);
        // print_r($request->post);
        // print_r($request->cookie);
        // print_r($request->files);
        // print_r($request->header);
        // print_r($request->server);
    
        $response->cookie("User", "Swoole");
        $response->header("X-Server", "Swoole");
        $response->end("<h1>Hello Swoole!</h1>");
    });
    
    $server->start();
    

    swoole_http_server继承自swoole_server,是一个完整的http服务器实现。

    注意:swoole_http_server对Http协议的支持并不完整,建议仅作为应用服务器。并且在前端增加Nginx作为代理:

    server {
        root /data/wwwroot/;
        server_name local.swoole.com;
    
        location / {
            proxy_http_version 1.1;
            proxy_set_header Connection "keep-alive";
            proxy_set_header X-Real-IP $remote_addr;
            if (!-e $request_filename) {
                proxy_pass http://127.0.0.1:9501;
            }
        }
    }
    

    WebSocketServer

    swoole增加了内置的WebSocket服务器支持,通过几行PHP代码就可以写出一个异步非阻塞多进程的WebSocket服务器。

    <?php
    $server = new swoole_websocket_server("0.0.0.0", 9052);
    
    $server->on('Start', function (swoole_websocket_server $server) {
        swoole_set_process_name("swoole_websocket_server");
        echo "Server Start... \n";
    });
    
    $server->on('WorkerStart', function (swoole_websocket_server $server, $worker_id){
        if ($server->worker_id == 0){
            swoole_timer_tick(2000, function ($timer_id) { //2000ms
                echo "tick-2000ms\n";
            });
        }
    });
    
    $server->on('Open', function (swoole_websocket_server $server, $request) {
        echo "server: handshake success with fd:{$request->fd}\n";
    });
    
    $server->on('Message', function (swoole_websocket_server $server, $frame) {
        echo "receive from fd:{$frame->fd}:{$frame->data}\n";
        $server->push($frame->fd, "Hello fd:{$frame->fd}, I'm Server.\n");
    });
    
    $server->on('Close', function ($ser, $fd) {
        echo "client fd:{$fd} closed\n";
    });
    
    $server->start();
    

    WebSocket客户端

    最简单的是使用JS编写:

    <script>
        socket = new WebSocket('ws://192.168.99.100:9052/'); 
        socket.onopen = function(evt) { 
            // 发送一个初始化消息
            socket.send('I am the client and I\'m listening!'); 
        }; 
    
        // 监听消息
        socket.onmessage = function(event) { 
            console.log('Received a message: ', event.data); 
            alert(event.data);
        }; 
    
        // 监听Socket的关闭
        socket.onclose = function(event) { 
            console.log('Socket has closed',event); 
        }; 
    
        socket.onerror = function(evt) { 
            console.log('onerror',event); 
        }; 
    </script>
    

    进程模型

    我们来使用实例进行分析:

    <?php
    $server = new \swoole_server("0.0.0.0",9053);//tcp_server
    
    $server->set([
        'daemonize' => false,//是否后台运行
        'log_file' => 'swoole.log',
        // 'worker_num' => 2,
    ]);
    
    $server->on('connect', function ($serv, $fd){ 
        echo "client connect. fd is {$fd}\n";
    });
    
    $server->on('receive', function ($serv, $fd, $from_id, $data){
        echo "client connect. fd is {$fd}\n";
    });
    
    $server->on('close', function ($serv, $fd){
        echo "client close. fd is {$fd}\n";
    });
    
    // 以下回调发生在Master进程
    $server->on("start", function (\swoole_server $server){
        echo "On master start.\n";
    });
    $server->on('shutdown', function (\swoole_server $server){
        echo "On master shutdown.\n";
    });
    
    // 以下回调发生在Manager进程
    $server->on('ManagerStart', function (\swoole_server $server){
        echo "On manager start.\n";
    });
    $server->on('ManagerStop', function (\swoole_server $server){
        echo "On manager stop.\n";
    });
    
    // 以下回调也发生在Worker进程
    $server->on('WorkerStart', function (\swoole_server $server, $worker_id){
        echo "Worker start\n";
    });
    $server->on('WorkerStop', function(\swoole_server $server, $worker_id){
        echo "Worker stop\n";
    });
    $server->on('WorkerError', function(\swoole_server $server, $worker_id, $worker_pid, $exit_code){
        echo "Worker error\n";
    });
    
    $server->start();
    

    我们使用 pstree -ap PID查看swoole进程数:

    [root@9355490fe5da /]# pstree -ap 235
    php,235 tcp_server.php
    |-php,236 tcp_server.php
    |   |-php,239 tcp_server.php
    |   `-php,240 tcp_server.php
    

    发现有4个进程。按PID从小到大分别是 Master进程、Manager进程、Worker进程(2个)。

    基于此,我们简单梳理一下,当执行的start方法之后,发生了什么:

    • 守护进程模式下,当前进程fork出Master进程,然后退出,Master进程触发OnMasterStart事件。
    • Master进程启动成功之后,fork出Manager进程,并触发OnManagerStart事件。
    • Manager进程启动成功时候,fork出Worker进程,并触发OnWorkerStart事件。

    非守护进程模式下,则当前进程直接作为Master进程工作。

    所以,一个最基础的Swoole Server,至少需要有3个进程,分别是Master进程、Manager进程和Worker进程。

    事实上,一个多进程模式下的Swoole Server中,有且只有一个Master进程;有且只有一个Manager进程;却可以有n个Worker进程。

    Master进程 是一个多线程进程,其中有一组非常重要的线程,叫做Reactor线程(组)。

    每当一个客户端连接上服务器的时候,都会由Master进程从已有的Reactor线程中,根据一定规则挑选一个,专门负责向这个客户端提供维持链接、处理网络IO与收发数据等服务。

    Manager进程 ,某种意义上可以看做一个代理层。

    它本身并不直接处理业务,其主要工作是将Master进程中收到的数据转交给Worker进程,或者将Worker进程中希望发给客户端的数据转交给Master进程进行发送。

    Manager进程还负责监控Worker进程,如果Worker进程因为某些意外挂了,Manager进程会重新拉起新的Worker进程。

    Worker进程 其实就是处理各种业务工作的进程,Manager将数据包转交给Worker进程,然后Worker进程进行具体的处理,并根据实际情况将结果反馈给客户端。

    参考资料

    相关文章

      网友评论

          本文标题:Swoole入门

          本文链接:https://www.haomeiwen.com/subject/rueqcftx.html