libevent-Reactor设计模式【1】

一、Libevent概述

1、简介

Libevent 是一个用C语言编写的、轻量级的开源高性能事件通知库,主要有以下几个亮点:事件驱动( event-driven),高性能;轻量级,专注于网络,不如 ACE 那么臃肿庞大;源代码相当精炼、易读;跨平台,支持 Windows、 Linux、 *BSD 和 Mac Os;支持多种 I/O 多路复用技术, epoll、 poll、 dev/poll、 select 和 kqueue 等;支持 I/O,定时器和信号等事件;注册事件优先级。

Libevent 已经被广泛的应用,作为底层的网络库;比如 memcached、 Vomit、 Nylon、 Netchat等等。

二、两个重要的结构体

1、struct event

2、struct event_base

三、libevent常用接口

1、event_init( )函数:初始化事件集合

(1)函数原型

原型:struct event_base *event_init(void)

(2)函数实现
cpp 复制代码
struct event_base *event_init(void)
{
  struct event_base *base = event_base_new_with_config(NULL);
 
  if (base == NULL) {
     event_errx(1, "%s: Unable to construct event_base", __func__);
     return NULL;
  }
 
  current_base = base;
 
  return (base);
}

(3)函数作用

初始化事件集合,其实就是调用了event_base_new_with_config( )函数,创建event_base对象,并且赋值给了全局变量struct evdns_base *current_base。

2、event_set( )函数:初始化事件

(1) 函数原型

原型:void event_set(struct event *ev, evutil_socket_t fd, short events, void (*callback)(evutil_socket_t, short, void *), void *arg);

参数:

1)事件

2)关联的文件描述符

3)事件类型

4)回调函数

5)回调函数的参数

函数实现

cpp 复制代码
void event_set(struct event *ev, evutil_socket_t fd, short events, void (*callback)(evutil_socket_t, short, void *), void *arg)
{
  int r;
  r = event_assign(ev, current_base, fd, events, callback, arg);
  EVUTIL_ASSERT(r == 0);
}
(3)函数作用:

初始化event事件(其实就是给结构体ev的成员赋值)

  • fd表示事件对应的文件描述符,
  • events表示事件的类型,
  • callback是回调函数(即当fd满足条件时调用该函数),
  • arg表示给回调函数传递的参数。

3、event_add( )函数:把事件添加到集合

(1)函数原型

原型:int event_add(struct event *ev, const struct timeval *tv);

cpp 复制代码
int event_add(struct event *ev, const struct timeval *tv)
{
  int res;
  if (EVUTIL_FAILURE_CHECK(!ev->ev_base)) {
    event_warnx("%s: event has no event_base set.", __func__);
    return -1;
  }
  EVBASE_ACQUIRE_LOCK(ev->ev_base, th_base_lock);
  res = event_add_nolock_(ev, tv, 0);
  EVBASE_RELEASE_LOCK(ev->ev_base, th_base_lock);
  return (res);
}

(3)函数作用

1.将event注册到event_base的I/O多路复用要监听的事件中;

2.将event注册到event_base的已注册事件链表中;

3.如果传入了超时时间,则删除旧的超时时间,重新设置,并将event添加到event_base的小根堆中;

如果没有传入超时时间,则不会添加到小根堆中。

只有步骤1成功,才会执行步骤2和3;否则什么都没做,直接返回,保证不会改变event的状态。

4、event_dispatch( )函数:监听事件

这个函数会让程序陷入死循环, 如果集合中没有事件可以监听,则返回

例子1:IO事件

  • 1-fifo.c
cpp 复制代码
#include <stdio.h>                                                                    
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <event.h>
#include <fcntl.h>
/*
   当监听的事件满足条件的时候,会触发回调函数,通过回调函数读取数据
 */
void fifo_read(evutil_socket_t fd, short events, void *arg) {
    char buf[32] = {0};
    int ret = read(fd, buf, sizeof(buf));
    if (-1 == ret) {
        perror("read");
        exit(1);
    }   

    printf("从管道读取: %s\n", buf);
}

int main() {
    int ret = mkfifo("fifo.tmp", 00700);
    if (-1 == ret) {
        perror("mkfifo");
        exit(1);
    }

    int fd = open("fifo.tmp", O_RDONLY);
    if (-1 == fd) {
        perror("open");
        exit(1);
    }
    
    // 创建事件
    struct event ev;

    // 初始化事件集合
    event_init();

    // 初始化事件(把fd和事件ev绑定)
    // 参数:事件、关联的文件描述符、事件类型、回调函数、回调函数参数
    event_set(&ev, fd, EV_READ | EV_PERSIST, fifo_read, NULL);

    //把事件添加到集合
    event_add(&ev, NULL);

    //开始监吿
    event_dispatch();  //死循玿 如果集合中没有事件可以监听,则返囿
    
    exit(0);
} 
  • 1-write_fifo.c
cpp 复制代码
#include <stdio.h>                                                                    
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

int main()
{
    int fd = open("fifo.tmp", O_WRONLY);
    if (-1 == fd) 
    {   
        perror("open");
        exit(2);
    }   

    char buf[128] = {0};

    while (1)
    {
        scanf("%s", buf);

        if (write(fd, buf, strlen(buf)) == -1)
        {
            perror("write");
            break;
        }

        if (!strcmp(buf, "bye"))
            break;

        memset(buf, 0, 128);
    }

    close(fd);

    return 0;
}

运行结果:

5、event_base_new( )函数:创建事件集合

(1)函数原型

原型:struct event_base *event_base_new(void);

(2)函数实现
cpp 复制代码
struct event_base *event_base_new(void)
{
  struct event_base *base = NULL;
  struct event_config *cfg = event_config_new();
  if (cfg) {
    base = event_base_new_with_config(cfg);
    event_config_free(cfg);
  }
  return base;
}

(3)函数作用

创建event_base对象

注意:采用event_base_new( )创建出来的事件集合,最后要用 event_base_free(base)释放掉,因为event_base_new( )是在堆空间上进行创建的。

(4)event_base_new( )与event_init( )的区别

这两个函数都会创建一个事件集合

event_init( )创建的是一个全局的事件集合

event_base_new( )创建的是一个局部的事件集合

event_init( )函数实现是由event_base_new( )封装而成的

6、event_base_free( )函数:释放事件集合

用于释放event_base_new( )函数创建的集合

7、event_assign( )函数:初始化事件

(1)函数原型:

原型:int event_assign(struct event *ev, struct event_base *base, evutil_socket_t fd, short events, void (*callback)(evutil_socket_t, short, void *), void *arg)

(2)参数介绍

1)事件

2)事件集合

3)关联的文件描述符

4)事件类型

5)回调函数

6)回调函数的参数

(3)函数作用

将指定事件集合中的事件与某一文件描述符进行关联

(4)event_assign( )与event_set( )的区别

event_assign( )可以指定事件集合;

event_set( )不能指定事件集合,默认采用event_init( )创建的全局的事件集合;

8、event_base_dispatch( )函数:监听事件

可监听事件集合当中的事件,和event_dispatch( )的作用相同

(1)event_base_dispatch( )与event_dispatch( )的区别

event_base_dispatch( )可以指定监听哪个事件集合;

event_dispatch( )不能指定事件集合,默认监听event_init( )创建的全局的事件集合;

9、event_del( )函数:把事件从集合中删除

原型:event_del(struct event *ev);

相关推荐
李广坤7 小时前
状态模式(State Pattern)
设计模式
李广坤8 小时前
观察者模式(Observer Pattern)
设计模式
李广坤9 小时前
中介者模式(Mediator Pattern)
设计模式
李广坤9 小时前
迭代器模式(Iterator Pattern)
设计模式
李广坤10 小时前
解释器模式(Interpreter Pattern)
设计模式
阿无,12 小时前
java23种设计模式之前言
设计模式
Asort13 小时前
JavaScript设计模式(八):组合模式(Composite)——构建灵活可扩展的树形对象结构
前端·javascript·设计模式
数据智能老司机13 小时前
数据工程设计模式——数据基础
大数据·设计模式·架构
笨手笨脚の16 小时前
设计模式-代理模式
设计模式·代理模式·aop·动态代理·结构型设计模式
Overboom1 天前
[C++] --- 常用设计模式
开发语言·c++·设计模式