当前位置:   article > 正文

Libevent 简述

libevent

目录

安装libevent

查看libevent头文件

查看libevent库文件

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

Libevent框架

<1>创建event_base

<2>创建事件event

常规事件event

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

添加事件到event_base

将事件从base上拿下

释放事件

未决和非未决

带缓冲区的事件bufferevent

bufferevent

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

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

禁用、启动缓冲区

<3>将事件添加到base上

<4>循环监听事件满足

停止循环

<5>释放event_base

<6>其他函数

查看当前系统支持哪些多路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

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

查看libevent头文件

/usr/local/include

查看libevent库文件

/usr/local/lib

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

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

Libevent框架

<1>创建event_base

  1. struct event_base {
  2. const struct eventop *evsel;
  3. void *evbase;
  4. int event_count; /* counts number of total events */
  5. int event_count_active; /* counts number of active events */
  6. int event_gotterm; /* Set to terminate loop */
  7. int event_break; /* Set to terminate loop immediately */
  8. /* active event management */
  9. struct event_list **activequeues;
  10. int nactivequeues;
  11. /* signal handling info */
  12. struct evsignal_info sig;
  13. struct event_list eventqueue;
  14. struct timeval event_tv;
  15. struct min_heap timeheap;
  16. struct timeval tv_cache;
  17. };

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

  1. struct event_base *event_base_new(void);
  2. struct event_base *base = event_base_new();

<2>创建事件event

  libevent 的基本操作单元是事件。每个事件代表一组条件的集合,这些条件包括:
<1>文件描述符已经就绪,可以读取或者写入
<2>文件描述符变为就绪状态, 可以读取或者写入 ( 仅对于边沿触发 IO)
<3>超时事件
<4>发生某信号
<5>用户触发事件 

常规事件event

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

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

添加事件到event_base

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

将事件从base上拿下

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

释放事件

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

未决和非未决

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

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

带缓冲区的事件bufferevent

bufferevent 由一个底层的传输端口(如 套接字 ),一个读取缓冲区和一个写入缓冲区组成。与通常的事件在底层传输端口已经就绪,可以读取或者写入的时候执行回调不同的是,bufferevent 在读取或者写入了足够量的数据之后调用用户提供的回调。
有多种共享公用接口的bufferevent类型,编写本文时已存在以下类型:
<1>基于 套接字 bufferevent : 使用 event_* 接口作为后端 , 通过 底层流式套接字发送或者接收数据 的 bufferevent
<2>异步 IO bufferevent : 使用 Windows IOCP 接口 , 通过底层流式套接字发送或者接收数据的bufferevent( 仅用于 Windows, 试验中 )
<3>过滤型 bufferevent : 将数据传输到底层 bufferevent 对象之前 , 处理输入或者输出数据的 bufferevent: 比如说 , 为了压缩或者转换数据。
<4>成对的 bufferevent : 相互传输数据的两个 bufferevent

bufferevent

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

 

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

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

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

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

  1. /*
  2. bufev: bufferevent_socket_new() 返回值
  3. readcb: 设置bufferevent读缓冲, 对应回调
  4. writecb: 设置bufferevent写缓冲, 对应回调 ,可传NULL
  5. eventcb: 设置事件回调。 也可传NULL
  6. cbarg:上述回调函数使用的参数
  7. */
  8. void bufferevent_setcb(struct bufferevent *bufev,
  9. bufferevent_data_cb readcb,
  10. bufferevent_data_cb writecd,
  11. bufferevent_event_cb eventcb,
  12. void *cbarg);

readcb对应的回调函数

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

writecb对应的回调函数

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

eventcb对应的回调函数

  1. typedef void(*bufferevent_event_cb)(struct bufferevent *bev,
  2. 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的

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

<3>将事件添加到base上

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

<4>循环监听事件满足

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

停止循环

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

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

<5>释放event_base

void event_base_free(struct event_base *base);

<6>其他函数

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

  1. //返回:字符指针数组
  2. 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,就需要进行重新初始化。

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

设置event_base优先级

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

  1. /*
  2. 成功时这个函数返回0,失败时返回-1。base是要修改的event_base,n_priorities是要支持的优先级数目,这个数目至少为1.每个新的事件可用的优先级将从0(最高)到n_priorities-1(最低)。
  3. */
  4. 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

  1. #include <stdio.h>
  2. #include <unistd.h>
  3. #include <stdlib.h>
  4. #include <sys/types.h>
  5. #include <sys/stat.h>
  6. #include <string.h>
  7. #include <fcntl.h>
  8. #include <event2/event.h>
  9. //对操作处理函数
  10. void read_cb(evutil_socket_t fd, short what, void *arg){
  11. //读管道
  12. char buf[1024] = {0};
  13. int len = read(fd, buf, sizeof(buf));
  14. printf("read event: %s \n", what & EV_READ ? "Yes" : "No");
  15. printf("data len = %d, buf = %s\n", len, buf);
  16. sleep(1);
  17. }
  18. //读管道
  19. int main(int argc, const char* argv[]){
  20. unlink("myfifo");
  21. //创建有名管道 0664:设置fifo权限
  22. mkfifo("myfifo", 0664);
  23. //open file
  24. int fd = open("myfifo", O_RDONLY | O_NONBLOCK);
  25. if(fd == -1){
  26. perror("open error");
  27. exit(1);
  28. }
  29. //创建个event_base
  30. struct event_base *base = NULL;
  31. base = event_base_new();
  32. //创建事件
  33. struct event* ev = NULL;
  34. ev = event_new(base, fd , EV_READ | EV_PERSIST, read_cb, NULL);
  35. //添加事件
  36. event_add(ev, NULL);
  37. //事件循环
  38. event_base_dispatch(base);
  39. //释放资源
  40. event_free(ev);
  41. event_base_free(base);
  42. close(fd);
  43. return 0;
  44. }

write_fifo

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <unistd.h>
  4. #include <string.h>
  5. #include <sys/types.h>
  6. #include <sys/stat.h>
  7. #include <fcntl.h>
  8. #include <event2/event.h>
  9. //对操作处理函数
  10. void write_cb(evutil_socket_t fd, short what, void *arg){
  11. //write管道
  12. char buf[1024] = {0};
  13. static int num = 0;
  14. sprintf(buf, "hello,world-%d\n", num++);
  15. write(fd, buf, strlen(buf)+1);
  16. sleep(1);
  17. }
  18. //写管道
  19. int main(int argc, char *argv[]){
  20. //open file
  21. int fd = open("myfifo", O_WRONLY | O_NONBLOCK);
  22. if(fd == -1){
  23. perror("open error");
  24. exit(1);
  25. }
  26. //写管道
  27. struct event_base* base = NULL;
  28. base = event_base_new();
  29. //创建事件
  30. struct event* ev = NULL;
  31. //检测的写缓冲区是否有空间写
  32. //ev = event_new(base, fd, EV_WRITE, write_cb, NULL);
  33. ev = event_new(base, fd, EV_WRITE | EV_PERSIST, write_cb, NULL);
  34. //添加事件
  35. event_add(ev, NULL);
  36. //事件循环
  37. event_base_dispatch(base);
  38. //释放资源
  39. event_free(ev);
  40. event_base_free(base);
  41. close(fd);
  42. return 0;
  43. }
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Gausst松鼠会/article/detail/458468
推荐阅读
相关标签
  

闽ICP备14008679号