初识libevent

简单流程图

在这里插入图片描述
以上是使用libevent实现一个简单通信的基本流程图。

创建、注册、删除事件

使用libevent函数之前需要分配一个或多个event_base结构体。
每个event_base结构体持有一个事件集合,可以检测确定哪个事件是激活的。

如果需要多个线程检测I/O,则需要为每个线程都分配一个event_base结构体。

每个event_base都有一种用于检测哪种事件已经就绪的“方法”,或者说后端。
可以识别的方法有:

  • select
  • poll
  • epoll等

用户禁止某些特定的后端的方法:

1、配置环境变量
比如说,要禁止kqueue后端,可以设置EVENT_NOKQUEUE环境变量。

2、用编程的方法禁止后端:
看下面关于event_config_avoid_method() 的说明


1、创建默认的event_base:event_base_new()

event_base_new()函数分配并且返回一个新的具有默认设置的event_base。
函数会检测环境变量,返回一个event_base的指针。如果发生错误,会返回NULL。

选择各种方法时,函数会选择OS支持最快的方法。

接口:

struct event_base *event_base_new(void)

2、释放event_base:event_base_free()

使用完event_base之后,要在程序的最后需要对event_base进行释放

接口:

void event_base_free(struct event_base *base)

注意:
这个函数不会释放当前与event_base关联的任何事件,或者关闭他们的套接字,或者释放任何指针


3、创建事件:event_new()

event_new()试图分配和构造一个用于base的新事件。
该函数出错时返回NULL

struct event *event_new(
	struct event_base *base,	//event_base_new的返回值
	evutil_socket_t fd,		//文件描述符 - int
	short what,		           //宏:可监听的事件标志
	event_callback_fn cb,	//事件的回调处理函数
	void *arg		//回调函数传参
)

//事件回调处理函数
typedef void (*event_callback_fn)(evutil_socket_t, short, void *)

事件标志:

标志含义
EV_TIMEOUT这个标志表示某超时时间流逝后事件成为激活的。构造事件时通常忽略此标志;可以在添加事件时设置超时,也可以不设置。超时发生时,回调函数的what参数带有这个标志
EV_READ表示指定的文件描述符已经就绪,可以读取的时候,事件将成为激活的
EV_WRITE表示指定的文件描述符已经就绪,可以写入的时候,事件将成为激活的
EV_SIGNAL用于实现信号检测
EV_PERSIST表示事件是“持久的“
EV_ET如果底层的event_base后端支持边沿触发事件,则事件应该是边沿触发的。这个标志影响EV_READ和EV_WRITE的语义

what参数是上述标志的集合。
如果fd非负,则它是将被观察其读写事件的文件。事件被激活时,libevent将调用cb函数,传递这些参数:文件描述符fd、表示所有被触发事件的位字段、以及构造事件时的arg参数。


4、event_free()

释放事件
对未决或激活状态的事件调用event_free()是安全的;在释放事件之前,函数将会使事件成为非激活和非未决的。

void event_free(struct event *event)

添加事件

注意:创建事件后,在将其添加到event_base之前,实际上是不能对其做任何操作的,需要使用event_add()将事件添加到event_base里。

5、event_add()

所有新创建的事件都处于已初始化和非未决状态,调用event_add()可以使其成为未决的。

非未决状态:没有资格被处理

未决状态:有资格被处理但是还没有被处理

//成功返回0,失败返回-1
int event_add(
	struct event *ev,	//添加的事件
	const struct timeval *tv	//设置超时的时间
)


struct timeval {         
        time_t       tv_sec;     /* seconds */          
        suseconds_t   tv_usec; /* microseconds */   
        };

参数:
tv:

  • NULL:添加的事件不会超时
  • tv={0, n}:设置的时间;
    微妙指定超时时间

添加事件循环

一旦有了一个已经注册某些事件的event_base,就需要让libevent等待事件并且通知事件的发生

6、event_base_loop()
 #define EVLOOP_ONCE					0x01 //事件未被触发时,阻塞等待
#define EVLOOP_NONBLOCK				0x02 //非阻塞的方式来做事件检测,不关心事件是否被触发了
#define EVLOOP_NO_EXIT_NO_EMPTY		0x04 //没有事件的时候,不会退出轮询检测

//成功返回0,失败返回-1
int event_base_loop(
	struct event_base *base,	
	int	 flags	
)

默认情况下,该函数运行event_base直到其中已经没有注册的事件为止。
循环执行的时候,函数重复地检查是否有任何已经注册的事件被触发。

比如说,该事件的文件描述符已经就绪,就可以读取了;或者超时事件的超时时间即将到达。如果有事件被触发,函数标记被触发的事件为“激活的”,并且执行这些事件。

在flag参数中设置一个或多个标志就可以改变event_base_loop()的行为。

  • 如果设置了EVLOOP_ONCE,循环将等待某些事件成为激活的,执行激活事件直到没有更多事件可以执行
  • 如果设置了EVLOOP_NONBLOCK,循环不会等待事件被触发。循环将仅仅检测是否有事件已经就绪,可以立即触发,如果有,则执行事件的回调函数
7、event_base_dispatch()

等同于没有设置标志的event_base_loop(),所以循环将一直进行,直到已经没有注册的事件了;或者,调用了event_base_loopbreak()或event_base_loopexit()为止

int event_base_dispatch
(	
struct event_base *base	//event_base_new的返回值
)

退出事件循环函数

如果想在移除所有已注册的事件之前停止活动的事件循环,可以调两个稍有不同的函数。
这两个函数都:成功返回0,失败返回-1

8、event_base_loopexit()

该函数让event_base在给定时间后停止循环。
如果tv参数为NULL,event_base会立即停止循环,没有延时。
如果event_base当前正在执行任何激活事件的回调,则回调会继续运行,直到执行完所有激活事件的回调函数才退出

int event_base_loopexit(
	struct event_base *base,
	const struct timeval *tv
);

//参数:
	struct timeval{
		long tv_sec;        //秒
		long tv_usec;      //微秒
		};
9、event_base_loopbreak()

一旦调用,event_base立即退出循环
它与event_base_loopexit(base, NULL)的不同之处在于,如果event_base当前正在执行激活事件的回调,它将在执行完当前正在处理的事件后立即退出。

int event_base_loopbreak(struct event_base *base)

注意:event_base_loopexit(base, NULL)和event_base_loopbreak(base)在事件循环没有运行时的行为不同:
前者安排下一次事件循环在下一轮回调完成后立即停止(就好像自带EVLOOP_ONCE标志调用一样);后者却仅仅停止当前正在运行的循环,如果事件循环没有运行,则没有任何效果。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值