一、初识
1、libevent介绍
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等等。
2、安装
官网:libevent
我这里用的是2.1.8版本,linux使用的是ubuntu20.4。使用原码安装。
(1)解压
(2)./configure # 检查安装环境 生成 makefile
(3)make # 生成 .o 和 可执行文件
(4)sudo make install # 将必要的资源cp置系统指定目录。
3、检查是否安装成功
进入sample路径下
这里有一些小demo可以测试书否安装成功
这样即表示安装成功。
4、查看安装路径
头文件在include里面
5、框架相关的不常用函数
查看支持哪些多路io
/*************************************************************************> File Name: 01event.c> Author: Winter> Created Time: 2022年02月17日 星期四 20时58分11秒************************************************************************/#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <event2/event.h>int main(int argc, char* argv[])
{struct event_base* base = event_base_new(); // 创建baseint i;const char** buff1;buff1 = event_get_supported_methods(); // 查看支持哪些多路iofor (i = 0; i < 10; i++) {printf("buff1[i] = %s\n", buff1[i]);}return 0;
}
注意编译时,添加-levent
查看当前使用的多路IO
/*************************************************************************> File Name: 01event.c> Author: Winter> Created Time: 2022年02月17日 星期四 20时58分11秒************************************************************************/#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <event2/event.h>int main(int argc, char* argv[])
{struct event_base* base = event_base_new(); // 创建basconst char *buff2;buff2 = event_base_get_method(base); // 查看当前使用的多路IOprintf("buff2 = %s\n", buff2);return 0;
}
二、libevent封装的框架思想
1、libevent框架
1. 创建 event_base (乐高底座)
2. 创建 事件evnet
3. 将事件 添加到 base上
4. 循环监听事件满足
5. 释放 event_base
(1)创建 event_base (乐高底座)
struct event_base *event_base_new(void);
struct event_base *base = event_base_new();
(2)创建 事件evnet
创建事件分为两种:常规事件(event_new)和带缓冲区的事件(bufferevent_socket_new)
常规事件 event --> event_new();
带缓冲区的事件 bufferevent --> bufferevent_socket_new();
(3)将事件 添加到 base上
int event_add(struct event *ev, const struct timeval *tv)
(4)循环监听事件满足
int event_base_dispatch(struct event_base *base);
(5)释放 event_base
event_base_free(base);
2、使用fifo读写(常规事件)
创建事件event
struct event *event_new(struct event_base *base,evutil_socket_t fd,short what event_callback_fn cb; void *arg);参数:base: event_base_new()返回值fd: 绑定到 event 上的 文件描述符what:对应的事件(r、w、e)EV_READ 一次 读事件EV_WRTIE 一次 写事件EV_PERSIST 持续触发。 结合 event_base_dispatch 函数使用,生效。cb:一旦事件满足监听条件,回调的函数。typedef void (*event_callback_fn)(evutil_socket_t fd, short, void *) arg: 回调的函数的参数。返回值:成功创建的 event
读操作
/*************************************************************************> File Name: myread.c> Author: Winter> Created Time: 2022年02月18日 星期五 21时07分03秒************************************************************************/#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <event2/event.h>// 回调函数
void read_cb(evutil_socket_t fd, short what, void* arg) {// 读管道char buff[1024] = {0};int len = read(fd, buff, sizeof(buff));printf("read event : %s \n", what & EV_READ ? "YES" : "NO");printf("data len = %d, buff = %s\n", len, buff);sleep(1);
}int main(int argc, char* argv[])
{unlink("myfifo");// 创建有名fifoint res = mkfifo("myfifo", 0664);if (res == -1) {perror("mkfifo error\n");exit(1);}// 打开fifoint fd = open("myfifo", O_RDONLY | O_NONBLOCK); // 非阻塞只读if (fd == -1) {perror("open error\n");exit(1);}// 创建event_basestruct event_base* base = event_base_new();// 创建事件 EV_PERSIST是持续读struct event* ev = event_new(base, fd, EV_READ | EV_PERSIST, read_cb, NULL);// struct event* ev = event_new(base, fd, EV_READ, read_cb, NULL);// 添加事件event_add(ev, NULL);// 事件循环event_base_dispatch(base); // while (1) { epoll }// 释放资源event_free(ev);event_base_free(base);close(fd);return 0;
}
写操作
/*************************************************************************> File Name: mywrite.c> Author: Winter> Created Time: 2022年02月18日 星期五 21时24分04秒************************************************************************/#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <event2/event.h>
#include <fcntl.h>// 回调函数
void write_cb(evutil_socket_t fd, short what, void* arg) {// 写管道char buff[1024] = {0};static int num = 0;sprintf(buff, "hello world - %d", num++);write(fd, buff, strlen(buff) + 1);sleep(1);
}int main(int argc, char* argv[])
{// 与myread.c配套,但是要先打开myread程序// 打开管道int fd = open("myfifo", O_WRONLY | O_NONBLOCK);if (fd == -1) {perror("open error\n");exit(1);}// 创建event_basestruct event_base* base = event_base_new();// 创建写事件 EV_PERSIST是持续写struct event* ev = event_new(base, fd, EV_WRITE | EV_PERSIST, write_cb, NULL);// struct event* ev = event_new(base, fd, EV_WRITE, write_cb, NULL);// 添加事件event_add(ev, NULL);// 事件循环event_base_dispatch(base);// 释放资源event_free(ev);event_base_free(base);close(fd);return 0;
}
测试
这里只测试了带有EV_PERSIST参数的event_new函数。