swoole 学习日记 One

版权声明:本文为勇哥原创文章,转载请注明出处哦!!! https://blog.csdn.net/woshihaiyong168/article/details/76955759


定义:

不扯犊子,swoole就是php的一个扩展(C编写的)

一般我们php 用于web端开发 对于http协议是非常清楚的,但是要想java那样 做一些socket 之类 的是实时的、在线的这种,如果我们使用http协议的话 只能使用ajax轮询,对于服务器来说得不偿失,这个时候就是swoole派上用场的时候,他可以实现php 做游戏、聊天室等之类的实时通讯的东西,大家也知道其实不只swoole可以让PHP实现这些功能,例如:workerman、meepops (PHP编写)都是非常不错的,相对于swoole来说这些对phper学习成本较高(就是有难度),但是swoole因为是纯c编写的比php编写的workerman、meepops来说速度功能方面要更加出色!!


1、环境安装(swoole扩展)

cd /usr/local/src
tar -zxvf v1.9.17.tar.gz
cd swoole-src-1.9.17/
/usr/local/php/bin/phpize
./configure --with-php-config=/usr/local/php/bin/php-config
make && make install
vim /usr/local/php/etc/php.ini
extension=swoole.so
service php-fpm reload


2、入门教程网址 点击打开链接
包含模块:

swoole_server

强大的TCP/UDP Server框架,多线程,EventLoop,事件驱动,异步,Worker进程组,Task异步任务,毫秒定时器,SSL/TLS隧道加密。

  • swoole_http_server是swoole_server的子类,内置了Http的支持
  • swoole_websocket_server是swoole_http_server的子类,内置了WebSocket的支持

swoole_client

TCP/UDP客户端,支持同步并发调用,也支持异步事件驱动。

swoole_event

EventLoop API,让用户可以直接操作底层的事件循环,将socket,stream,管道等Linux文件加入到事件循环中。

eventloop接口仅可用于socket类型的文件描述符,不能用于磁盘文件读写

swoole_async

异步IO接口,提供了 异步文件系统IO,异步DNS查询,异步MySQL等API。包括2个重要的子模块:

  • swoole_timer,异步毫秒定时器,可以实现间隔时间或一次性的定时任务
  • file,文件系统操作的异步接口

swoole_process

进程管理模块,可以方便的创建子进程,进程间通信,进程管理。

swoole_buffer

强大的内存区管理工具,像C一样进行指针计算,又无需关心内存的申请和释放,而且不用担心内存越界,底层全部做好了。

swoole_table

基于共享内存和自旋锁实现的超高性能内存表。彻底解决线程,进程间数据共享,加锁同步等问题。

swoole_table的性能可以达到单线程每秒读写50W次




编程注意点:

进程隔离

进程隔离也是很多新手经常遇到的问题。修改了全局变量的值,为什么不生效,原因就是全局变量在不同的进程,内存空间是隔离的,所以无效。所以使用swoole开发Server程序需要了解进程隔离问题。

  • 不同的进程中PHP变量不是共享,即使是全局变量,在A进程内修改了它的值,在B进程内是无效的
  • 如果需要在不同的Worker进程内共享数据,可以用RedisMySQL文件Swoole\TableAPCushmget等工具实现
  • 不同进程的文件句柄是隔离的,所以在A进程创建的Socket连接或打开的文件,在B进程内是无效,即使是将它的fd发送到B进程也是不可用的


onStart事件在Master进程的主线程中被调用。在此回调响应之前Swoole Server已进行了如下操作
  • 已创建了manager进程
  • 已创建了worker子进程
  • 已监听所有TCP/UDP端口
  • 已监听了定时器

接下来要执行

  • 主Reactor开始接收事件,客户端可以connect到Server
onStart回调中,仅允许echo、打印Log、修改进程名称。不得执行其他操作。onWorkerStart和onSta rt回调是在不同进程中并行执行的,不存在先后顺序。 可以在onStart回调中,将 $serv->master_pid$serv->manager_pid的值保存到一个文件中。这样可以编写脚本,向这两个PID发送信号来实现关闭和重启的操作。
从1.7.5+ Master进程内不再支持定时器,onMasterConnect/onMasterClose2个事件回调也彻底移除。Master进程内不再保留任何PHP的接口。
在onStart中创建的全局资源对象不能在worker进程中被使用,因为发生onStart调用时,worker进程已经创建好了。新创建的对象在主进程内,worker进程无法访问到此内存区域,因此全局对象创建的代码需要放置在swoole_server_start之前。

3.onWorkerStart

描述:Worker进程启动的回调
函数原型:

function onWorkerStart( swoole_server $servint $worker_id);
参数 描述
$serv swoole_server对象
$worker_id Worker进程的id

说明:此事件在worker进程/task_worker启动时发生。

发生PHP致命错误或者代码中主动调用exit时,Worker/Task进程会退出,管理进程会重新创建新的进程 onWorkerStart/onStart是并发执行的,没有先后顺序

通过$worker_id参数的值来,判断worker是普通worker还是task_worker。$worker_id>= $serv->setting['worker_num'] 时表示这个进程是task_worker。
如果想使用swoole_server_reload实现代码重载入,必须在workerStart中require你的业务文件,而不是在文件头部。在onWorkerStart调用之前已包含的文件,不会重新载入代码。
可以将公用的,不易变的php文件放置到onWorkerStart之前。这样虽然不能重载入代码,但所有worker是共享的,不需要额外的内存来保存这些数据。
onWorkerStart之后的代码每个worker都需要在内存中保存一份 $worker_id是一个从0-$worker_num之间的数字,表示这个worker进程的ID $worker_id和进程PID没有任何关系

4.onConnect

描述:新连接接入时的回调
函数原型:

function onConnect( swoole_server $servint $fd, int $from_id);
参数 描述
$serv swoole_server对象
$fd 连接的描述符
$from_id reactor的id,无用

说明:有新的连接进入时,在worker进程中回调。onConnect/onClose这2个回调发生在worker进程内,而不是主进程。如果需要在主进程处理连接/关闭事件,请注册onMasterConnect/onMasterClose回调。onMasterConnect/onMasterClose回调总是先于onConnect/onClose被执行

5.onClose

描述:连接关闭时的回调
函数原型:

function onClose( swoole_server $servint $fd, int $from_id);
参数 描述
$serv swoole_server对象
$fd 连接的描述符
$from_id reactor的id,无用

说明:TCP客户端连接关闭后,在worker进程中回调此函数。无论close由客户端发起还是服务器端主动调用swoole_server_close关闭连接,都会触发此事件。 因此只要连接关闭,就一定会回调此函数。

6.onTask

描述:task_worker进程处理任务的回调
函数原型:

function onTask(swoole_server $serv, int $task_id, int $from_id, string $data);
参数 描述
$serv swoole_server对象
$task_id 任务ID
$from_id 来自于哪个worker进程
$data 任务内容

说明:在task_worker进程内被调用。worker进程可以使用swoole_server_task函数向task_worker进程投递新的任务。可以直接将任务结果字符串通过return方式返回给worker进程。worker进程将在onFinish回调中收到结果。注:如果serv->set(array('task_worker_num' => 8)) task_id 并不是从1-8 而是递增的。

7.onFinish

描述:task_worker进程处理任务结束的回调
函数原型:

function onFinish(swoole_server $serv, int $task_id, string $data);
参数 描述
$serv swoole_server对象
$task_id 任务ID
$data 任务结果

说明:在此函数中会收到任务处理的结果,通过task_id和worker_id来区分不同的任务。

8.onTimer

描述:定时器触发的回调
函数原型:

function onTimer(swoole_server $serv, int $interval);
参数 描述
$serv swoole_server对象
$interval 定时的间隔

说明:定时器被触发时,该函数被调用。通过interval来区分不同时间间隔的定时器。



php 服务端 demo:
<?php
class Server
{
    private $serv;

    public function __construct()
    {
        $this->serv = new swoole_websocket_server("0.0.0.0", 2888);
        $this->serv->set(array(
            'worker_num' => 4,
            'daemonize' => false,
            'max_request' => 10000,
            'dispatch_mode' => 2,
            'debug_mode' => 1,
            'task_worker_num' => 4
        ));
        //启动开始
        $this->serv->on('Start', array($this, 'onStart'));

        //与onStart同级
        $this->serv->on('WorkerStart', array($this, 'onWorkerStart'));

        //webSocket open 连接触发回调
        $this->serv->on('open', array($this, 'onOpen'));

        //webSocket send 发送触发回调
        $this->serv->on('message', array($this, 'onMessage'));

        //webSocket close 关闭触发回调
        $this->serv->on('Close', array($this, 'onClose'));

        //tcp连接 触发 在 webSocket open 之前回调
        $this->serv->on('Connect', array($this, 'onConnect'));

        //tcp 模式下(eg:telnet ) 发送信息才会触发  webSocket 模式下没有触发
        $this->serv->on('Receive', array($this, 'onReceive'));

        // task_worker进程处理任务的回调   处理比较耗时的任务
        $this->serv->on('Task', array($this, 'onTask'));

        // task_worker进程处理任务结束的回调
        $this->serv->on('Finish', array($this, 'onFinish'));

        // 服务开启
        $this->serv->start();


    }


    public function onStart(swoole_websocket_server $serv)
    {
//        $this->serv->tick(1000, function() {
//            echo 1;
//        });
        echo "Start\n";
    }

    public function onWorkerStart(swoole_websocket_server $serv,$worker_id)
    {
        //判断是worker进程还是 task_worker进程 echo 次数 是worker_num+task_worker_num
        if($worker_id<$this->serv->setting['worker_num']){
            echo  'worder'.$worker_id."\n";
        }else{
            echo  'task_worker'.$worker_id."\n";
        }
   //     echo "workerStart{$worker_id}\n";
    }


    public function onOpen(swoole_websocket_server $serv,$request)
    {
        echo "server: handshake success with fd{$request->fd}\n";
    }

    public function onMessage(swoole_websocket_server $serv,$frame)
    {
        echo "receive from {$frame->fd}:{$frame->data},opcode:{$frame->opcode},fin:{$frame->finish}\n";
        $param = array(
            'fd' => $frame->fd
        );
        $this->serv->task( json_encode( $param ) );
//            $server->push($frame->fd, "this is server");
    }


    public function onConnect( $serv, $fd, $from_id ) {
        echo "Client {$fd} connect\n";
        echo "{$from_id}\n";
    }

    public function onReceive( swoole_websocket_server $serv, $fd, $from_id, $data ) {
        echo "Get Message From Client {$fd}:{$data}\n";
        // send a task to task worker.
//        $param = array(
//            'fd' => $fd
//        );
//        $serv->task( json_encode( $param ) );
        echo "Continue Handle Worker\n";
    }


    public function onClose($serv, $fd)
    {
        echo "Client {$fd} close connection\n";
    }


    public function onTask($serv, $task_id, $from_id, $data)
    {
        echo "This Task {$task_id} from Worker {$from_id}\n";
        echo "Data: {$data}\n";
        for ($i = 0; $i < 10; $i++) {
            sleep(1);
            echo "Taks {$task_id} Handle {$i} times...\n";
        }
        $fd = json_decode($data, true)['fd'];
        echo  "Data in Task {$task_id}";
//        $serv->send($fd, "Data in Task {$task_id}");
        return "Task {$task_id}'s result";
    }

    public function onFinish($serv,$task_id, $data) {
        echo "Task {$task_id} finish\n";
        echo "Result: {$data}\n";
    }

}

$server = new Server();




猜你喜欢

转载自blog.csdn.net/woshihaiyong168/article/details/76955759