前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >玩转 PHP 网络编程全套之 libevent 框架首篇

玩转 PHP 网络编程全套之 libevent 框架首篇

作者头像
桶哥
发布2020-05-22 17:39:43
7760
发布2020-05-22 17:39:43
举报
文章被收录于专栏:PHP饭米粒

LIBEVENT框架

此框架的扩展是LIBEVENT,php手册地址libevent,该框架了封装I/O事件,定时事件,中断信号事件,内核I/O复用函数支持EPOLL,POLL,SELECT,DEVPOLL,KQUEUE。框架官方网站libvent官网以下项目使用了该框架

框架涉及到的知识点说明【非常重要,否则可能会复制粘贴跑起来了,但是相关知识点并没有完全的理解,更谈不上熟悉php撸的workerman框架了^_^】

  • TCP/IP
  • thread 线程
  • I/O复用
  • 事件处理模式
    • reactor 模式
    • Proactor 模式
  • 并发模式
    • 半同步/半异步模式
  • 定时器
  • 中断信号
  • I/O事件
  • 事件多路分发器EventDeumultiplexer
  • 事件处理器EventHandler
  • 底层知识
    • 网卡驱动
    • ARP协议【mac硬件物理地址交换】
    • 网络数据帧
  • 同步/异步线程

本人注解的网络框架libevent源码内核原理分析 相关测试源码和分析流程以及笔记可联系本人获取

源码框架安装说明

php libevent扩展安装地址

如果认真看过PHP手册的人安装php扩展是非常容易的. 本人安装的扩展是event2.2.1版本

先运行个示例玩

代码语言:javascript
复制
<?php

class MyListenerConnection {
    private $bev, $base;

    public function __destruct() {
        //将读写和异常回调清空同时释放BufferEvent相关内置的数据
        $this->bev->free();
    }
    public function __construct($base, $fd) {
        $this->base = $base;

        //创建BufferEvent对象
        //此对象内置了读写事件处理器,但并没有添加到I/O事件池中
        //同时该对象分别创建input/outpu对象【内置创建】主要用于数据读写【接收和发送】
        $this->bev = new EventBufferEvent($base, $fd, EventBufferEvent::OPT_CLOSE_ON_FREE);

        //设置读写异常回调函数 【写回调并未设置】
        $this->bev->setCallbacks(array($this, "echoReadCallback"), NULL,
            array($this, "echoEventCallback"), NULL);

        //将内置的写事件处理器添加到I/O事件池中,并且向内核事件表注册读就绪事件
        if (!$this->bev->enable(Event::READ)) {
            echo "Failed to enable READ\n";
            return;
        }
    }
    public function echoReadCallback($bev, $ctx) {
        //读就绪事件发生后,内置的读事件处理器运行,然后运行此函数
        //同时调用output,并把input【内置的读事件处理器读取的数据会放入到此input对象中】
        //直接将接受的数据写入到客户端
        $bev->output->addBuffer($bev->input);

    }
    public function echoEventCallback($bev, $events, $ctx) {
        //异常回调
        if ($events & EventBufferEvent::ERROR) {
            echo "Error from bufferevent\n";
        }

        if ($events & (EventBufferEvent::EOF | EventBufferEvent::ERROR)) {
            //$bev->free();
            $this->__destruct();
        }
    }
}

class MyListener {
    public $base, $listener, $socket;
    private $conn = array();

    public function __destruct() {
        foreach ($this->conn as &$c) $c = NULL;
    }

    public function __construct($port) {
        //创建event_base对象
        //内置了I/O事件处理器池和信号事件处理器池
        //同时也内置的定时时间堆
        $this->base = new EventBase();
        if (!$this->base) {
            echo "Couldn't open event base";
            exit(1);
        }

        //创建socket 并监听同时将此socket的读就绪事件注册到【经过I/O复用函数即事件多路分发器EventDemultiplexer管理】
        //此socket 内置了监听事件处理器,客户端连接后,会调用此事件处理器,然后再运行用户设置的回调函数acceptConnCallBack函数
        //EventListener::OPT_CLOSE_ON_FREE | EventListener::OPT_REUSEABLE 标志位
        //EventListener::OPT_CLOSE_ON_FREE 此参数会关闭低层连接socket
        //EventListener::OPT_REUSEABLE 和前面说过的socket 选项有关【不清楚请翻阅之前我写过的东西】
        //后面2个参数为ip和端口用于生成socket
        $this->listener = new EventListener($this->base,
            array($this, "acceptConnCallback"), $this->base,
            EventListener::OPT_CLOSE_ON_FREE | EventListener::OPT_REUSEABLE, -1,
            "0.0.0.0:$port");

        if (!$this->listener) {
            echo "Couldn't create listener";
            exit(1);
        }

        //设置此socket事件处理器的错误回调
        $this->listener->setErrorCallback(array($this, "accept_error_cb"));
    }

    public function dispatch() {
        //内置了event_base_loop进行循环处理
        //主要是调用如epoll的epoll_wait函数进行监听
        //当任意I/O产生了就绪事件则会通知此进程
        //此进程将会遍历就绪的I/O事件读取文件描述符
        //并从I/O事件处理器池读取对应的事件处理器队链
        //再将事件处理器插入到请求队列中
        //两从请求队列中获取到事件并循环一一处理
        //从而运行指定的回调函数
        $this->base->dispatch();
    }

    /**
     * @param $listener 上面的监听器
     * @param $fd 产生就绪事件的文件描述符
     * @param $address 客户端地址
     * @param $ctx 用户自定义传递的参数
     */
    public function acceptConnCallback($listener, $fd, $address, $ctx) {

        $base = $this->base;
        $this->conn[] = new MyListenerConnection($base, $fd);
    }

    public function accept_error_cb($listener, $ctx) {
        $base = $this->base;

        fprintf(STDERR, "Got an error %d (%s) on the listener. "
            ."Shutting down.\n",
            EventUtil::getLastSocketErrno(),
            EventUtil::getLastSocketError());

        $base->exit(NULL);
    }
}

$port = 12345;

if ($argc > 1) {
    $port = (int) $argv[1];
}
if ($port <= 0 || $port > 65535) {
    exit("Invalid port");
}

$l = new MyListener($port);
//event_base_loop持续阻塞
//直到内核事件表中的I/O事件就绪产生才会运行相对的回调函数
$l->dispatch();

框架内部用到的数据结构和PHP关联的对象

代码语言:javascript
复制
new EventBase() 对应c内部的event_base结构体
new EventListener 对应内部的evconnlistener结构体
new EventBufferEvent 对应内部的bufferevent结构体
更多相关的内容请阅读本人注解的内核libevent框架,不然你可能对这些知识点感到烧脑子
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-05-15,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 PHP饭米粒 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • LIBEVENT框架
  • 框架涉及到的知识点说明【非常重要,否则可能会复制粘贴跑起来了,但是相关知识点并没有完全的理解,更谈不上熟悉php撸的workerman框架了^_^】
  • 源码框架安装说明
  • 先运行个示例玩
  • 框架内部用到的数据结构和PHP关联的对象
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档