0.在Linux系统上安装Libevent库
使用命令:CentOS安装Libevent库(含示例代码)
sudo yum install libevent-devel
Ubuntu/Debian:
sudo apt install libevent-dev
1.什么是Libevent?
理解Libevent之前首先理解信号,它是进程间通信的一种机制。它是一种软中断,用于宣布某种事件,比如我要中断一个进程,Linux信号默认以SIG开头,多达64种,具体各种信号及其默认操作与目的详见链接。在Linux上关于信号内容,请使用man 7 signal查看。
其中有一个信号SIGINT,它的编号是2,通常在用户按下 `Ctrl+C `时被发送给前台进程,目的是中断它。
具体使用方法:
#include<signal.h>
#include<iostream>
#include<unistd.h>
#include<stdlib.h>
#include<stdio.h>
using namespace std;
void my_handler(int sig){
if(sig==SIGINT){
cout<<"Received SIGINT."<<endl;
exit(0);
}
}
int main(){
if(signal(SIGINT, my_handler)==SIG_ERR){//signal失败将返回SIG_ERR
perror("signal");
return 1;
} // 我们使用signal()注册了信号处理函数:当程序收到SIGINT信号后调用my_handler();
while (1){
cout << "while(1)" << endl;
sleep(2);
}
}
如上,我们使用signal注册了信号处理函数,在程序接收到SIGINT信号也就是2号信号后调用my_handler函数,打印并释放资源。
而Libevent作为C语言实现的网络库,他使得你可以在某个信号(比如SIGINT)到达 / 某个文件描述符上有事件(比如读事件写事件)到达 / 超时 这三种情况发生时,执行回调函数。它支持我们在网络编程中学习的 epoll poll select 。相当于做了一个封装使得我们更好使用它们。我们仅需熟悉它的几个常用的API就可以在屏蔽底层细节的情况下实现功能。
头文件是#include<event2/event.h>或者#include<event.h>
编译命令g++ 你的文件名 -o 可执行文件名 -levent
我们将会用到的接口:
event_init(void);
event_dispatch(void);
evsignal_new();//底层是 event_new();
evtimer_new();//底层是 event_new();
event_add();
event_free();
event_base_free();
下面我们使用示例代码详细解释它们的功能。
2.示例代码:
我们先使用evsignal_new再使用event_new。他俩的区别我写在了注释中。
#include<stdio.h>//printf
#include<event.h>
#include<stdlib.h>//exit
#include<signal.h>//SIGINT
void fun1(int fd,short ev,void* arg){
if(ev==EV_SIGNAL){
printf("sig==%d\n", fd);
}
}
void fun2(int fd,short ev,void* arg){
if(ev&EV_TIMEOUT){
printf("timeout\n");
}
}
int main(){
struct event_base *base = event_init();//初始化事件基础结构
if(base==NULL)exit(1);
struct event *sig_ev = evsignal_new(base, SIGINT, fun1, NULL);//SIGINT信号接受会调用fun1,而不是终止程序
// 这其实是一个宏 #define evsignal_new(b, x, cb, arg) event_new((b), (x), EV_SIGNAL | EV_PERSIST, (cb), (arg))
//宏替换后,EV_PERSIST被添加,也就是说SIGINT信号触发后,自动添加,这样就可以连续触发。这与evtimer_new不一样,它虽然也是宏替换但是没有EV_PERSIST标识
if(sig_ev==NULL)exit(1);
event_add(sig_ev, NULL);//创建好sig_ev事件之后,将它添加到base中
struct event *time_ev = evtimer_new(base, fun2, NULL);//创建定时器事件,超时调用fun2
if(time_ev==NULL)exit(1);
struct timeval tv{3,0};
event_add(time_ev, &tv);//tv中的时间到期之后调用time_ev指向的fun2函数
event_base_dispatch(base);//启动事件循环,开始处理事件
//清理两个事件和事件基础结构base
event_free(time_ev);
event_free(sig_ev);
event_base_free(base);
return 0;
}
编译:
g++ 你的文件名 -o 可执行文件名-levent
运行起来后:
你键入Ctrl+c,打印sig=2,因为底层有EV_PERSIST,所以SIGINT触发后,还会继续添加。
到达5秒后,将打印time out,但是超时事件不再被触发。
使用event_new:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <time.h>
#include <event.h>
#include <signal.h>
void sig_cb(int fd, short ev, void* arg)
{
if ( ev & EV_SIGNAL )
{
printf("sig=%d\n",fd);
}
}
void time_cb(int fd, short ev, void* arg)
{
if ( ev & EV_TIMEOUT )
{
printf("time out\n");
}
}
int main()
{
struct event_base * base = event_init();
if ( base == NULL )
{
exit(1);
}
struct event *sig_ev = event_new(base, SIGINT, EV_SIGNAL, sig_cb, NULL); // 只触发一次,必须通过event_add()重新添加才能重新触发
// struct event *sig_ev = event_new(base, SIGINT, EV_SIGNAL | EV_PERSIST, sig_cb, NULL); // 设置了 EV_PERSIST 标志,事件触发后自动重新添加
if ( sig_ev == NULL )
{
exit(1);
}
event_add(sig_ev,NULL);
struct event *time_ev = event_new(base, -1, EV_TIMEOUT, time_cb, NULL);//只触发一次,必须通过event_add()重新添加才能重新触发
// struct event *time_ev = event_new(base, -1, EV_TIMEOUT | EV_PERSIST, time_cb, NULL); // 设置了 EV_PERSIST 标志,事件触发后自动重新添加
if ( time_ev == NULL )
{
exit(1);
}
struct timeval tv = {2,0};
event_add(time_ev,&tv);
event_base_dispatch(base);
event_free(time_ev);
event_free(sig_ev);
event_base_free(base);
}
两个事件都是一次触发。不再添加。
当我们放开注释的两行后,两个事件都会被触发多次。
我个人认为,event_new更易用。


&spm=1001.2101.3001.5002&articleId=142859291&d=1&t=3&u=b012062a9a85466d8b6ae4cdd1d21778)
1694

被折叠的 条评论
为什么被折叠?



