【Linux】Libevent库---event

libevent框架:

    1. 创建 event_base        (乐高底座)

        struct event_base *event_base_new(void);

        struct event_base *base = event_base_new();

    2. 创建 事件evnet,   事件为“非未决态”(没有资格被处理)。 

        常规事件 event    --> event_new(); 

        struct event *event_new(struct event_base *base, evutil_socket_t fd, short what, event_callback_fn cb, void *arg);

        bufferevent --> bufferevent_socket_new();


    3. 将事件 添加到 base上,事件转化为 “未决态”(有资格被处理,但还未被处理)。    

        int event_add(struct event *ev, const struct timeval *tv)

    4. 循环监听事件满足     ==>   while(1){      epoll_wait( epfd,  ...);    }

        int event_base_dispatch(struct event_base *base);

            event_base_dispatch(base);

    5. 释放 event_base

        event_base_free(base);

.

未决态与非未决态

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

【Linux】Libevent库---event_第1张图片

        所有事件具有相似的生命周期。调用 libevent 函数设置事件并且关联到event_base 之后, 事件进入“已初始化(initialized)”状态。此时可以将事件添加到event_base 中,这使之进入“未决(pending)”状态。在未决状态下,如果触发事件的条件发生(比如说,文件描述 符的状态改变,或者超时时间到达 ),则事件进入“激活(active)”状态,(用户提供的)事件回调函数将被执行。如果配置为“持久的(persistent)”,事件将保持为未决状态。否则, 执行完回调后,事件不再是未决的。删除操作可以让未决事件成为非未决(已初始化)的 ; 添加操作可以让非未决事件再次成为未决的。


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

// event_add
	int event_add(
				struct event *ev, 
				const struct timeval *tv
				); 
- tv:参数 Value
NULL: 没有定时时间,只要事件被触发, 对应的回调就会被调用。
tv = {0, n} 设置的定时时间,即使在该时间段内检测的事件没被触发, 只要时间到达之后, 不管有无读写事件,回调函数还是会被调用。

read_fifo.c

#include
#include
#include
#include
#include
#include
#include
#include


// typedef void (*event_callback_fn)(evutil_socket_t, short, void *);
void read_cb(int fd, short what, void* arg){
	char buf[1024] = {0};    //清空buf;这一步很重要,不做看不出现象。

	read(fd, buf, sizeof(buf));


	printf("read event is %s \n", what & EV_READ ? "YES" : "NO");
	printf("read content is %s \n\n", buf);

	sleep(2);
}


int main(int argc, char* argv[])
{
	unlink("myfifo");

	// 创建用于通信的管道
	mkfifo("myfifo", 0644);

	int fd = open("myfifo", O_RDONLY | O_NONBLOCK);


	// 创建event_base对象
	struct event_base *base = event_base_new();


	// 创建event对象,ev为 “非未决态”(没有资格被处理)。
	// struct event *event_new(struct event_base *base, evutil_socket_t fd, short what, event_callback_fn cb, void *arg);
	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);
	printf("read over!\n");
	return 0;
}

write_fifo.c

#include
#include
#include
#include
#include
#include
#include
#include


// typedef void (*event_callback_fn)(evutil_socket_t, short, void *);
void write_cb(int fd, short what, void* arg){
	char buf[] = "hello libevent";

	write(fd, buf, strlen(buf));

	printf("write event is %s \n", what & EV_WRITE ? "YES" : "NO");

	sleep(1);
}


int main(int argc, char* argv[])
{
	int fd = open("myfifo", O_WRONLY | O_NONBLOCK);


	// 创建event_base对象
	struct event_base *base = event_base_new();


	// 创建event对象
	// struct event *event_new(struct event_base *base, evutil_socket_t fd, short what, event_callback_fn cb, void *arg);
	struct event *ev = NULL;
	ev = event_new(base, fd, EV_WRITE | EV_PERSIST, write_cb, NULL);
	// 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);
	printf("write over!\n");
	return 0;
}

持续写,持续读 的结果:

ev = event_new(base, fd, EV_WRITE | EV_PERSIST, write_cb, NULL);

ev = event_new(base, fd, EV_READ | EV_PERSIST, read_cb, NULL);

【Linux】Libevent库---event_第2张图片

问题:

        写事件怎么触发的?

回答:

        缓冲区可写就触发了。

  • fifo缓冲区没满,对应写事件文件描述符就会处于就绪态,然后dispatch扫描时触发写事件。
  • 写事件fifo只要有空间就能被触发,触发后调用回调函数,回调函数里再write。
  • read事件要判断缓冲区非空才触发。

非持续写,持续读 的结果:

ev = event_new(base, fd, EV_WRITE, write_cb, NULL);

ev = event_new(base, fd, EV_READ | EV_PERSIST, read_cb, NULL);

 注意:

        这里每次读管道之前,都用代码,清空 buf 缓冲区。

char buf[1024] = {0};    //清空buf;这一步很重要,不做看不出现象。

【Linux】Libevent库---event_第3张图片

只触发了一次写,持续触发读。

参考链接:

详解libevent网络库(一)---框架的搭建

你可能感兴趣的:(【Linux】,linux,算法,数据库)