1.libevent 是一个库,底层封装了select,poll,epoll,用起来更方便
libevent底层用的是多线程。-->ldd+可执行文件(可以查看用了哪些共享库)
2.libevent(主要就是检测定时器,信号,i/o方法)的执行流程:
对于组件来说①句柄就是文件描述符②事件多路分发器:i/o方法实现③事件处理器和事件具体处理器:回调函数(事件具体处理器:I/O框架库提供的事件处理器通常是一个接口,用户需要继承它来实现自己的事件处理器,即具体事件处理器。因此,事件处理器中的回调函数一般被声明为虚函数,以支持用户的扩展。此外,事件处理器一般还提供一个get handle方法,它返回与该事件处理器关联的句柄。那么,事件处理器和句柄有什么关系?当事件多路分发器检测到有事件发生时,它是通过句柄来通知应用程序的。因此,我们必须将事件处理器和句柄绑定,才能在事件发生时获取到正确的事件处理器。)④Reactor:
3.libevent简单的示例(了解接口,参数):libevent检测定时器,信号:
libevent提供的事件(编译要加库-levent):
event_new:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <event.h>//libevent
#include <signal.h>//信号
#include <time.h>//定时器
void sig_cb(int fd, short ev, void* arg)//描述符,事件类型,传给的参数
{
if ( ev & EV_SIGNAL)//确保是信号的事件EV_SIGNAL
{
printf("sig=%d\n",fd);
}
}
void timeout_cb(int fd, short ev, void* arg)
{
if( ev & EV_TIMEOUT)//确保是定时事件EV_TIMEOUT
{
printf("time out\n");
}
}
int main()
{
//1 定义libevent实例
struct event_base * base = event_init();//初始化实例
//--------------------------------------------------信号事件
//2 定义事件-->信号事件
//struct event * sig_ev = evsignal_new(base,SIGINT,sig_cb,NULL);//底层默认是永久性事件EV_PERSIST
struct event * sig_ev = event_new(base,SIGINT,EV_SIGNAL,sig_cb,NULL);//sig_cb为回调函数,传给的参数是空,EV_SIGNAL为将永久性事件改为信号事件即只触发一次
//3 添加事件到Libevent
event_add(sig_ev,NULL);//事件的指针,超时时间(NULL)
//---------------------------------------------------定时的事件
struct timeval tv = {5,0};//定时5s,每5s触发一次
//定义事件-->定时的事件
//struct event * time_ev = evtimer_new(base,timeout_cb,NULL);//底层为定时事件EV_TIMEOUT
struct event * time_ev = event_new(base,-1,EV_TIMEOUT|EV_PERSIST,timeout_cb,NULL);//描述符定时没描述符为-1,EV_TIMEOUT|EV_PERSIST为给定时事件加上永久性事件
//添加事件到libevent
event_add(time_ev,&tv);
//---------------------------------------------------事件循环
//事件循环---内部调用select/poll/epoll循环检测事件
event_base_dispatch(base);//启动循环,参数为实例,没有事件自动结束-->底层调用epoll_wait会阻塞
event_free(time_ev);//释放定时事件
event_free(sig_ev);//释放信号事件
event_base_free(base);//将bsae释放
exit(0);
}
4.libevent与tcp,作为服务器端(i/o事件):
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <event.h>
#include <time.h>
struct mess//为每一个描述符准备这个结构体空间,存放事件,延长生长周期,(存放描述符所要的数据)
{
struct event * ev;//事件-->存放事件,记住事件
//char data[1024];//自定义-->存数据
//int c;//自定义-->存放描述符的值
};
int socket_init();
void recv_data(int c, short ev, void* arg)//接收数据
{
struct mess * p = (struct mess*)arg;
if( ev & EV_READ)
{
char buff[128] = {0};
int n = recv(c,buff,127,0);
if ( n <= 0 )
{
event_free(p->ev);//libevent移除 event_free()
free(p);
close(c);
printf("client close\n");
return;
}
printf("buff=%s\n",buff);
send(c,"ok",2,0);
}
}
void accept_client(int sockfd, short ev, void* arg)//接收客户端,接收后得到的连接套接子,要先进行libevent检测后再返回
{
struct event_base* base = (struct event_base*)arg;//参数为arg
if( ev & EV_READ )//现阶段只关注读
{
int c = accept(sockfd,NULL,NULL);
if ( c < 0 )
{
return;
}
//定义事件-->这样移除没法移除,移除得是个指针
//struct event * c_ev=event_new(base,c,EV_READ|EV_PERSIST,recv_data,NULL);
//event_add(c_ev,NULL);//添加事件到libevent
struct mess * p = (struct mess*)malloc(sizeof(struct mess));
//定义事件
p->ev = event_new(base,c,EV_READ|EV_PERSIST,recv_data,p);//放入结构体
event_add(p->ev,NULL);//添加事件到libevent
//p->c = c;//p所需的其他数值可以继续添加
}
}
int main()
{
int sockfd = socket_init();
if ( sockfd == -1 )
{
exit(1);
}
//1 定义libevent实例
struct event_base * base = event_init();
//添加sockfd,到libevent
struct event* sock_ev = event_new(base,sockfd,EV_READ|EV_PERSIST,accept_client,base);//有读事件进行这一行
event_add(sock_ev,NULL);//将新事件加到libevent中
event_base_dispatch(base);//启动事件循环 while( 1 ) epoll_wait, 阻塞
event_free(sock_ev);
event_base_free(base);
close(sockfd);
exit(0);
}
int socket_init()
{
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)
{
printf("bind err\n");
return -1;
}
res = listen(sockfd,5);
if( res == -1)
{
return -1;
}
return sockfd;
}