libevent是一个基于事件触发的网络库
libevent特点和优势:
- 事件驱动,高性能,线程安全
- 轻量级,专注于网络;
- 跨平台,支持 Windows、Linux、Mac Os等;
- 支持多种 I/O多路复用技术, epoll、poll、dev/poll、select 和kqueue 等;
- 支持 I/O,定时器和信号等事件;
基于Reactor模式实现的I/O框架库包含了如下几个组件:
-
句柄(Handler)
-
事件多路分发器(EventDemultiplexer)
-
事件处理器(EventHandler)
-
具体的事件处理器(ConcreteEventHandler)、Reactor。
-
句柄
作用:当内核检测到就绪事件时,它将通过句柄来通知应用程序这一事件在Linux下,I/O事件对应的句柄是文件描述符
信号事件对应的句柄就是信号值
-
事件多路分发器
本质:封装了的系统支持的各种I/O复用系统调用方法:事件多路分发器的demutiplex方法是等待事件的核心函数,内部调用的就是select、poll、 epoll_wait等函数
-
事件处理器
通常包含一个或多个回调函数 -
具体的事件处理器
I/O框架库提供的事件处理器通常是一个接口,用户需要继承它来事件自己的事件处理器,即具体事件处理器。 -
Reactor
-
handle_events
执行事件循环。等待事件,然后依次处理所有就绪事件对应的事件处理器 -
register_handler
调用事件多路分发器的register_event方法来往事件多路分发器中 注册一个事件 -
remove_handler
调用事件多路分发器的remove_event方法来 删除事件多路分发器中的一个事件
举例:
#include<stdlib.h>
#include<assert.h>
#include<stdio.h>
#include<string.h>
#include<unistd.h>
#include<event.h>
#include<signal.h>
#include<sys/time.h>
void sig_cb(int fd,short ev,void *arg)//信号回调函数
{
printf("sig=%d\n",fd);
}
void time_cb(int fd,short ev,void *arg)//超时回调函数
{
printf("time out\n");
}
int main()
{
struct event_base *base=event_init();//创建libevent实例
assert(base!=NULL);
/* 创建信号事件处理器 */
// struct event *sig_ev=evsignal_new(base,SIGINT,sig_cb,NULL);
struct event *sig_ev=event_new(base,SIGINT,EV_SIGNAL|EV_PERSIST,sig_cb,NULL);
assert(sig_ev!=NULL);
event_add(sig_ev,NULL);//将事件处理器添加到注册事件队列中,并将该事件处理器对应的事件添加到事件多路分发器中
/*创建超时事件处理器*/
// struct event *time_ev=evtimer_new(base,time_cb,NULL);
struct event *time_ev=event_new(base,-1,EV_TIMEOUT|EV_PERSIST,time_cb,NULL);
struct timeval tv={3,0};
event_add(time_ev,&tv);
/*事件无限循环,等待就绪事件并执行事件处理*/
event_base_dispatch(base);
/*当事件处理完将事件移除反应堆,释放系统资源*/
event_free(sig_ev);
event_free(time_ev);
event_base_free(base);
}
注意:
- 我们通过连接libevent库来进行管理libevent库,所以在使用gcc或者g++编译的时候最后需要加上-levent
- EV_PERSIST可以让注册的事件在执行完后不被删除,直到调用event_del()删除.
libevent实现的服务器端
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<assert.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<poll.h>
#include<sys/epoll.h>
#include<fcntl.h>
#include<signal.h>
#include<errno.h>
#include<event.h>
#include<sys/time.h>
#define MAXFD 1024
struct event * arr[MAXFD]={NULL};
void arr_add(int fd,struct event *ev)
{
if(fd<0||fd>=MAXFD)
{
return;
}
arr[fd]=ev;//将事件对应的事件处理器保存起来
}
struct event *arr_find_ev(int fd)//查找fd对应的事件处理器
{
if(fd<0||fd>=MAXFD)
{
return NULL;
}
struct event *ptr=arr[fd];
arr[fd]=NULL;
return ptr;
}
void recv_cb(int fd,short ev,void *arg)
{
if(ev &EV_READ)
{
char buff[128]={0};
int n=recv(fd,buff,127,0);
if(n<=0)//客户端要求关闭
{
event_free(arr_find_ev(fd));//释放fd对应的事件处理器
close(fd);//关闭文件描述符
printf("one client over\n");
return ;
}
printf("buff(%d)=%s\n",fd,buff);
send(fd,"ok",2,0);
}
}
void accept_cb(int fd,short ev,void *arg)
{
if(ev & EV_READ)//读事件
{
struct event_base *base=(struct event_base *)arg;
struct sockaddr_in caddr;
int len=sizeof(caddr);
int c=accept(fd,(struct sockaddr *)&caddr,&len);
printf("accept=%d\n",c);
if(c<0)
{
return ;
}
/*创建c对应的事件处理器*/
struct event *c_ev=event_new(base,c,EV_READ|EV_PERSIST,recv_cb,NULL);
if(c_ev==NULL)
{
close(c);
return ;
}
event_add(c_ev,NULL);//将c对应的事件处理器添加到注册事件队列中
arr_add(c,c_ev);
}
}
int main()
{
int sockfd=create_sockfd();
assert(sockfd!=-1);
struct event_base *base=event_init();
assert(base!=NULL);
struct event*sock_ev=event_new(base,sockfd,EV_READ|EV_PERSIST,accept_cb,base);
assert(sock_ev!=NULL);
event_add(sock_ev,NULL);
event_base_dispatch(base);
event_free(sock_ev);
event_base_free(base);
close(sockfd);
exit(0);
}
int create_sockfd()
{
int sockfd=socket(AF_INET,SOCK_STREAM,0);
if(sockfd==-1)
{
return -1;
}
struct sockaddr_in saddr;
memset(&saddr,0,sizeof(saddr));
saddr.sin_family=AF_INET;
saddr.sin_port=htons(6000);
saddr.sin_addr.s_addr=inet_addr("127.0.0.1");
int res=bind(sockfd,(struct sockaddr *)&saddr,sizeof(saddr));
if(res==-1)
{
return -1;
}
listen(sockfd,5);
return sockfd;
}