高级I/O框架libevent库简介

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;

}

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值