libevent
libevent 是一个开源的I/O框架库,在服务器编程中经常使用,libevent库底层将select或poll或epoll进行了封装。使用libevent库的目的是为了检测事件的。虽然libevent是一个库,只是将源代码编译后放在/usr/include的底下
使用libevent类似于使用一个库函数,只不过这个库函数是用户自己装上去的
libevent库处理的事件类型:
1.I/O事件
2.信号事件
3.定时事件
使用libevent库的步骤:
1.定libevent实例或框架
提供功能:
2.注册事件:
告诉libevent用户要关心哪类事件。一般注册的事件中会包含如下内容
1.I/O事件:关注的描述符 fd;关心的事件: r , w, err;有事件产生需要相应处理的回调函数fun()
2.信号事件:关注的信号代号 sig ;有信号产生相应相应处理的回调函数fun1()
3.定时事件:定时事件一般没有描述符,所以一般使用 “ -1” 表示;有事件产生相应相应处理的回调函数fun2()
3.事件循环:
用户将关注的事件都交付给了libevent实例,因此libevent需要进行检测。什么时间开始检测?当执行事件循环就会进行检测。事件循环一旦执行就会阻塞。libevent底层调用I/O复用方法对事件进行检测,一旦检测到有事件产生就会返回通知libevent实例,最终调用相应的回调函数进行处理
4.注销事件:
用户对于某个事件不想关注了可以进行注销,即移除.某个文件描述符关闭,需要将其移除
Reactor
示例一:定时事件与信号事件
示例描述:让libevent去检测定时事件,用户键盘Ctrl+C产生2号信号,收到信号就屏幕打印接收到该信号,定时5s,5s到了就打印 time out
细节处理:
单次事件:只检测一次,当产生一次信号,libevent检测到后调用完回调函数后就无事可干,会自动退出
永久性事件:检测到有事件产生后继续在进行检测,不会自动退出,除非用户主动让其退出
EV_PERSIST:永久性事件:需要循环进行检测的事件
预编译后就会进行宏替换:
宏展开:
编译程序时应该注意加后缀 -levent
示例2:tcp服务器与客户端连接
多个客户端连接tcp服务器端,使用libevent去检测描述符上的事件
服务器端:
当libevent检测到客户端关闭时就应该注销该客户端的文件描述符,否则会一直触发读事件(由于recv不会堵塞,当客户端关闭recv会返回0提示服务器,客户端已经关闭,因此libevent会一直检测到有读事件产生,因此会一直打印“ client close"
注销事件:
event_free();注销需要给出相应的事件,但是此时已经没有事件了,事件已经丢了
解决方法:
方法一:简单
将 ‘ c ’ 和 c_ev 做一个映射:类似于数组下标的对应关系,等到需要注销事件时就查找一下 fd 对应的事件地址是多少,free一下就可以
方法二:
动态申请一个指针变量,将 c_ev 的值放在该指针变量中。