Libevent 简述

目录

安装libevent

查看libevent头文件

查看libevent库文件

在配置阶段没有指定安装目录

Libevent框架

创建event_base

创建事件event

常规事件event

创建一个事件(非常重要!!!)

添加事件到event_base

将事件从base上拿下

释放事件

未决和非未决

带缓冲区的事件bufferevent

bufferevent

带缓冲区的事件创建、释放

给读写缓冲区设置回调(非常重要!!!)

禁用、启动缓冲区

将事件添加到base上

循环监听事件满足

停止循环

释放event_base

其他函数

查看当前系统支持哪些多路I/O

查看当前系统用的那个 多路I/O

查看fork后子进程使用的event_base

设置event_base优先级

实现Libevent和FIFO的读写

read_fifo

write_fifo


libevent是一个轻量级的开源高性能网络库基于"事件"异步通信模型。适用于windows、linux、bsd等多种平台(跨平台),内部使用select、epoll、kqueue等系统调用管理事件机制。著名分布式缓存软件memcached也是libevent based,而且libevent在使用上可以做到跨平台,而且根据libevent官方网站上公布的数据统计,似乎也有着非凡的性能。

安装libevent

//在本地目录解压安装包
tar zxvf libevent-2.1.8-stable.tar.gz//到解压好的安装包文件夹下执行安装过程
cd libevent-2.1.8-stable///执行./configure
./configure
make
sudo make install

查看libevent头文件

/usr/local/include

查看libevent库文件

/usr/local/lib

在配置阶段没有指定安装目录

gcc helloworld.c -o helloworld -l event //去掉lib和后缀.so(动态库)就是库名

Libevent框架

创建event_base

struct event_base { const struct eventop *evsel; void *evbase; int event_count; /* counts number of total events */ int event_count_active; /* counts number of active events */ int event_gotterm; /* Set to terminate loop */ int event_break; /* Set to terminate loop immediately */ /* active event management */ struct event_list **activequeues; int nactivequeues; /* signal handling info */ struct evsignal_info sig; struct event_list eventqueue; struct timeval event_tv; struct min_heap timeheap; struct timeval tv_cache; 
};

event_base_new()函数分配并且返回一个新的具有默认设置的event_base。函数会检测环境变量,返回一个到event_base的指针。若发生错误,则返回NULL。选择各种方法时,函数会选择OS支持的最快方法

struct event_base *event_base_new(void);struct event_base *base = event_base_new();

创建事件event

libevent 的基本操作单元是事件。每个事件代表一组条件的集合,这些条件包括:

文件描述符已经就绪,可以读取或者写入 文件描述符变为就绪状态, 可以读取或者写入 ( 仅对于边沿触发 IO) 超时事件

发生某信号

用户触发事件 

常规事件event

创建一个事件(非常重要!!!)

/*
base: event_base_new() 返回值
fd: 绑定到event上的文件描述符
what:对应所需执行的读、写、异常操作EV_READEV_WRITEEV_PERSIST持续触发 (可以理解为:while(read()) 或 while(write()))
cb:一旦事件满足监听条件,回调的函数typedef void(*event_callback_fn)(evutil_socket_t fd, short, void *)
arg:回调的函数的参数
返回值:成功创建的event
*/
struct event *event_new(struct event_base *base, evutil_socket_t fd, short what,event_callback_fn cb, void *arg);

添加事件到event_base

/*
ev: event_new() 函数返回的事件
tv:为NULL,不会超时。意为:一直等到事件被触发,回调函数会被调用为非0。等待期间,检查事件没有被触发,时间到,回调函数依旧会被调用
*/
int event_add(struct event *ev, const struct timeval *tv);

将事件从base上拿下

//ev:event_new()函数返回的事件
int event_del(struct event *ev);

释放事件

//成功:0, 失败:-1
int event_free(struct event *ev);

未决和非未决

未决:有资格被处理,但还没有被处理
非未决:没有资格处理

event_new --> event --> 非未决 --> event_add -->未决 --> dispath() && 监听事件被触发 --> 激活态 --> 执行回调函数 --> 处理态 --> 非未决 event_add && EV_PERSIST --> 未决 --> event_del --> 非未决

带缓冲区的事件bufferevent

bufferevent 由一个底层的传输端口(如 套接字 ),一个读取缓冲区和一个写入缓冲区组成。与通常的事件在底层传输端口已经就绪,可以读取或者写入的时候执行回调不同的是,bufferevent 在读取或者写入了足够量的数据之后调用用户提供的回调。 有多种共享公用接口的bufferevent类型,编写本文时已存在以下类型:

基于 套接字 bufferevent : 使用 event_* 接口作为后端 , 通过 底层流式套接字发送或者接收数据 的 bufferevent 异步 IO bufferevent : 使用 Windows IOCP 接口 , 通过底层流式套接字发送或者接收数据的bufferevent( 仅用于 Windows, 试验中 ) 过滤型 bufferevent : 将数据传输到底层 bufferevent 对象之前 , 处理输入或者输出数据的 bufferevent: 比如说 , 为了压缩或者转换数据。

成对的
bufferevent : 相互传输数据的两个 bufferevent

bufferevent

#include 原理:bufferevent有两个缓冲区:也是队列实现,缓冲区内部的数据只能读一次,读完就没有了。由于使用fifo,数据先进先出

 

读:有数据 --》 读回调函数read_cb()被调用 --》 使用bufferevent_read() --》 读数据
写:使用bufferevent_write() --》 向写缓冲中写数据 --》 该缓冲区有数据自动写出 --》 写完,回调函数write_cb()被调用

带缓冲区的事件创建、释放

/*
创建:
base:event_base_new 函数的返回值
fd: 跟bufferevent绑定的文件描述符。类比 event_new()
options: 
BEV_OPT_CLOSE_ON_FREE:释放 bufferevent 时关闭底层传输端口。这将关闭底层
套接字,释放底层bufferevent 等。
BEV_OPT_THREADSAFE:自动为 bufferevent 分配锁,这样就可以安全地在多个线程
中使用 bufferevent。
BEV_OPT_DEFER_CALLBACKS:设置这个标志时,bufferevent 延迟所有回调,如上所述
BEV_OPT_UNLOCK_CALLBACKS:默认情况下,如果设置 bufferevent 为线程安全的,则
bufferevent 会在调用用户提供的回调时进行锁定。设置这个选项会让 libevent在执行
回调的时候不进行锁定。
*/
struct bufferevent *bufferevent_socket_new(struct event_base *base,evutil_socket_t fd, enum bufferevent_options options);/*
释放:
bev: bufferevent_socket_new()的返回值
*/
void bufferevent_free(struct bufferevent *bev);

给读写缓冲区设置回调(非常重要!!!)

/*
bufev: bufferevent_socket_new() 返回值
readcb: 设置bufferevent读缓冲, 对应回调
writecb: 设置bufferevent写缓冲, 对应回调 ,可传NULL
eventcb: 设置事件回调。 也可传NULL
cbarg:上述回调函数使用的参数
*/
void bufferevent_setcb(struct bufferevent *bufev,bufferevent_data_cb readcb,bufferevent_data_cb writecd,bufferevent_event_cb eventcb,void *cbarg);

readcb对应的回调函数

typedef void (*bufferevent_data_cb)(struct bufferevent *bev, void *ctx);如: 
void read_cb(struct bufferevent *bev, void *arg){......bufferevent_read(); //读数据,类似read()的作用
}读数据:从bufferevent输入缓冲区 中 移除数据//通常用在readcb中,替代read()
size_t bufferevent_read(struct bufferevent *bufev, void *data, size_t size);//常用在bufferevent_read之后,替代write()
int bufferevent_write(struct bufferevent *bufev, const void *data, size_t size);

writecb对应的回调函数

非常不使用!!!!
如:
void write_cb(struct bufferevent *bev, void *arg){......
}

eventcb对应的回调函数

typedef void(*bufferevent_event_cb)(struct bufferevent *bev, short events, void *ctx);

events:
BEV_EVENT_READING:读取操作时发生某事件,具体是哪种事件请看其他标志。 BEV_EVENT_WRITING:写入操作时发生某事件,具体是哪种事件请看其他标志。 BEV_EVENT_ERROR : 操 作 时 发 生 错 误 。 关 于 错 误 的 更 多 信 息 , 请 调 用 EVUTIL_SOCKET_ERROR()。
BEV_EVENT_TIMEOUT:发生超时。
BEV_EVENT_EOF:遇到文件结束指示。
BEV_EVENT_CONNECTED:请求的连接过程已经完成。

禁用、启动缓冲区

默认:新建的bufferevent写缓冲是enable的。而,读缓冲是disable的

//通常用来启用bufferevent的read缓冲
void bufferevent_enable(struct bufferevent *bufev, short events);启用缓冲区//events: EV_READ、EV_WRITE、EV_READ|EV_WRITE
void bufferevent_disable(struct bufferevent *bufev, short events); 禁用缓冲区//获取缓冲区的禁用状态,需要借助& 来得到
short bufferevent_get_enabled(struct bufferevent *bufev);

将事件添加到base上

/*
ev: event_new() 函数返回的事件
tv:为NULL,不会超时。意为:一直等到事件被触发,回调函数会被调用为非0。等待期间,检查事件没有被触发,时间到,回调函数依旧会被调用
*/
int event_add(struct event *ev, const struct timeval *tv);

循环监听事件满足

int event_base_dispatch(struct event_base *base);
/*
base:event_base_new 函数的返回值
成功 :0, 失败 :-1只有event_new 中指定了 EV_PERSIST 才持续触发,否则只触发一次,就跳出循环
通常这样:EV_WRITE|EV_PERSIST 、EV_READ|EV_PERSIST
*/

停止循环

若想在移除所有已注册的事件之间停止活动的事件循环,可以调用两个稍有不同的函数。

//在指定时间后停止循环 tv:设置超时时间
int event_base_loopexit(struct event_base *base, const struct timeval *tv);//立即停止循环
int event_base_loopbreak(struct event_base *base);

释放event_base

void event_base_free(struct event_base *base);

其他函数

查看当前系统支持哪些多路I/O

//返回:字符指针数组
const char **event_get_supported_methods(void);

查看当前系统用的那个 多路I/O

const char * event_base_get_method(const struct event_base *base);

查看fork后子进程使用的event_base

不是所有事件后端都在调用fork()之后可以正确工作。所以,若在使用fork()或者其他相关系统调用启动新进程之后,希望在新进程中继续使用event_base,就需要进行重新初始化。

/*
成功:0,失败:-1
使用该函数后,父进程创建的base才能在子进程中生效
*/
int event_reinit(struct event_base *base);

设置event_base优先级

libevent支持为事件设置多个优先级。然而,event_base默认只支持单个优先级。可以调用event_base_priority_init()设置event_base的优先级数目。

/*
成功时这个函数返回0,失败时返回-1。base是要修改的event_base,n_priorities是要支持的优先级数目,这个数目至少为1.每个新的事件可用的优先级将从0(最高)到n_priorities-1(最低)。
*/
int event_base_priority_init(struct event_base *base, int n_priorities);

常量 EVENT_MAX_PRIORITIES 表示 n_priorities 的上限。调用这个函数时为 n_priorities 给出更大的值是错误的。

必须在任何事件激活之前调用这个函数,最好在创建event_base后立刻调用。

实现Libevent和FIFO的读写

read_fifo

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include //对操作处理函数
void read_cb(evutil_socket_t fd, short what, void *arg){//读管道char buf[1024] = {0};int len = read(fd, buf, sizeof(buf));printf("read event: %s \n", what & EV_READ ? "Yes" : "No");printf("data len = %d, buf = %s\n", len, buf);sleep(1);
}//读管道
int main(int argc, const char* argv[]){unlink("myfifo");//创建有名管道  0664:设置fifo权限mkfifo("myfifo", 0664);//open fileint fd = open("myfifo", O_RDONLY | O_NONBLOCK);if(fd == -1){perror("open error");exit(1);}//创建个event_basestruct event_base *base = NULL;base = event_base_new();//创建事件struct event* ev = NULL;ev = event_new(base, fd , EV_READ | EV_PERSIST, read_cb, NULL);//添加事件event_add(ev, NULL);//事件循环event_base_dispatch(base);//释放资源event_free(ev);event_base_free(base);close(fd);return 0;
}              

write_fifo

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include //对操作处理函数
void write_cb(evutil_socket_t fd, short what, void *arg){//write管道char buf[1024] = {0};static int num = 0;sprintf(buf, "hello,world-%d\n", num++);write(fd, buf, strlen(buf)+1);sleep(1);
}//写管道
int main(int argc, char *argv[]){//open fileint fd = open("myfifo", O_WRONLY | O_NONBLOCK);if(fd == -1){perror("open error");exit(1);}//写管道struct event_base* base = NULL;base = event_base_new();//创建事件struct event* ev = NULL;//检测的写缓冲区是否有空间写//ev = event_new(base, fd, EV_WRITE, write_cb, NULL);ev = event_new(base, fd, EV_WRITE | EV_PERSIST, write_cb, NULL);//添加事件event_add(ev, NULL);//事件循环event_base_dispatch(base);//释放资源event_free(ev);event_base_free(base);close(fd);return 0;
}


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部