libevent
可以处理I/O事件,信号事件(转化为I/O事件进行处理),以及定时事件。 I/O框架库:封装select,poll,epoll,提供了一个更加便捷的接口。(更高效,更稳定。)
- 基于Reactor模式实现:
(共有5各组件) 1.句柄 (学习,学语文,学数学,学英语,对应处理语文课本,数学课本,英语课本) I/O框架要处理的对象有: (I/O事件,信号事件,定时时间),统称:事件源 I/O事件对应的句柄是文件描述符,信号事件对应的句柄是信号值。 2.事件多路分发器(事件的到来时随机,异步的,无法程序何时收到一个客户的连接请求,获取这暂停信号),最好的办法就是,程序一直循环等待处理事件,每隔一段时间就访问一下,简单说就是通过统一接口调用select,poll,epoll_wait 来等待事件。(demultiplex方法就是这些函数的调用接口) 还需要:register_event,remove_event方法往事件多路分发器中,添加事件和删除事件。 3.事件处理器和具体事件处理器 事件处理器的功能:即执行回调(一个或多个)函数(handle_event)在事件循环中,I/O框架提供的事件处理器通常是接口,需要用户自己继承它,来实现自己的事件处理器,也就是具体的事件处理器。因此定义为虚函数,方便扩展。 (还提供了get_handle),返回和事件处理器相关的句柄。 (当事件多路分发器检测到有事件产生,会通过句柄来通知应用程序,接下来事件处理器才会去循环处理这些事件),因此句柄和事件处理器是绑定在一块的。 举个例子:比如I/O事件对应句柄是文件描述,而通过回调函数获取的文件描述符是就绪文件描述符, 举个例子,比如I/O函数检测到内核中有就绪事件,回调函数就去处理这些就绪时间,比如回调函数中封装了recv,就是通过recv去接收数据。 5.Reator(整个I/O框架库的核心) 提供的主要方法: 1.handle_event:执行事件的循环,重复:等待事件,依次处理就绪事件对应的事件处理器。 2.register_handler: 该方法通过调用时间多路分发器中的register_event方法来往时间多路分发器中添加事件 3.remove——hander:该方法通过调用时间多路分发器中的remove_event方法来往时间多路分发器中删除事件。 整个I/O框架处理事件如下图:
执行:stu@stu-virtual-machine:~/linux/day22$ gcc -o main main.c -levent ctrl + \ 结束程序 创建具体事件处理器(利用回调函数)在循环事件中执行
struct event *sig_ev = event_new(base,SIGINT,EV_SIGNAL|EV_PERSIST,sig_cb, NULL);
如果没有EV_PERSIT **sig只介入一次。**信号只触发一次
定时事件
struct event *time_ev = event_new(base,-1,EV_TIMEOUT|EV_PERSIST,time_cb,N ULL);
有EV_PERSIST ,可以一直处理定时事件 主动退出事件:
event_base_loopexit(base,&delay);
- 初始化一个libevent库,并保存返回指针
//定义实例框架,创建event_base对象,就可以使用Reactor中的方法
struct event_base *base = event_init();
assert(base != NULL)
- 首先对应用程序进行初始化event,设置好事件类型和回调函数
如信号事件,定时事件:
struct event *sig_ev = event_new(base,SIGINT,EV_SIGNAL,sig_cb,NULL);
也可以是:
void event_set(struct event *ev, int fd, short event, void (*cb)(int,
short, void *), void *arg)
ev :执行要初始化的 event 对象; fd :该 event 绑定的“句柄”,对于信号事件,它就是关注的信号; event :在该 fd 上关注的事件类型,它可以是 EV_READ , EV_WRITE , EV_SIGNAL ; cb :这是一个函数指针,当 fd 上的事件 event 发生时,调用该函数执行处理,它有三个参数, 调用时由 event_base 负责传入,按顺序,实际上就是 event_set 时的 fd, event 和 arg; arg :传递给 cb 函数指针的参数;
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();
assert(base != NULL);
struct event *sig_ev = event_new(base,SIGINT,EV_SIGNAL,sig_cb,NULL);
assert(sig_ev!=NULL);
event_add(sig_ev,NULL);
struct timeval tv = {2,0};
struct event *time_ev = event_new(base,-1,EV_TIMEOUT|EV_PERSIST,time_cb,NULL);
event_add(time_ev,&tv);
event_base_dispatch(base);
event_free(time_ev);
event_free(sig_ev);
event_base_free(base);
exit(0);
}
回调函数还是
struct event** p_ev = (struct event**)malloc(sizeof(struct event*));
*p_ev = event_new(base,c,EV_READ|EV_PERSIST,recv_cb,p_ev);
if(*p_ev == NULL)
{
return ;
}
event_add(*p_ev,NULL);
event_free(*p);
free(p);
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<event.h>
#include<assert.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<netinet/in.h>
//回调函数
int socket_init();
void recv_cb(int fd,short ev,void *arg)
{
struct event **p = (struct event**)arg;
if(p == NULL)
{
return ;
}
if(ev & EV_READ)
{
char buff[128] = {0};
int n = recv(fd,buff,127,0);
if(n <= 0)
{
event_free(*p);
free(p);
close(fd);
printf("client over\n");
}
else
{
printf("buff(%d) == %s\n",fd,buff);
send(fd,"ok",2,0);
}
}
}
//回调函数
void accept_cb(int fd,short ev,void *arg)
{
struct event_base *base = (struct event_base*)arg;
if(ev & EV_READ)
{
struct sockaddr_in caddr;
int len = sizeof(caddr);
int c = accept(fd,(struct sockaddr*)&caddr,&len);
if(c<0)
{
return ;
}
printf("accept c =%d\n",c);
struct event** p_ev = (struct event**)malloc(sizeof(struct event*));
*p_ev = event_new(base,c,EV_READ|EV_PERSIST,recv_cb,p_ev);
if(*p_ev == NULL)
{
return ;
}
event_add(*p_ev,NULL);
}
}
int main()
{
int sockfd = socket_init();
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);
exit(0);
}
int socket_init()
{
int sockfd = socket(AF_INET,SOCK_STREAM,0);
if(sockfd == -1)
{
return sockfd;
}
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;
}
res = listen(sockfd,5);
if(res == -1)
{
return -1;
}
return sockfd;
}
启动 :gcc -o ser ser.c -levent
|