一、初识

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();               // 创建base
        int i;

        const char** buff1;
        buff1 = event_get_supported_methods();       // 查看支持哪些多路io
        for (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();               // 创建bas
        const char *buff2;
        buff2 = event_base_get_method(base);                      // 查看当前使用的多路IO
        printf("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");
        // 创建有名fifo
        int res = mkfifo("myfifo", 0664);
        if (res == -1) {
                perror("mkfifo error\n");
                exit(1);
        }
        // 打开fifo
        int fd = open("myfifo", O_RDONLY | O_NONBLOCK);        // 非阻塞只读
        if (fd == -1) {
                perror("open error\n");
                exit(1);
        }

        // 创建event_base
        struct 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_base
        struct 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函数。

Logo

更多推荐