高性能I/O框架库Libevent

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/YL970302/article/details/83582492

一、I/O框架库概述:I/O框架库以库函数的形式,封装了较为底层的系统调用,给应程序提供了一组更便于使用的接口,这些库函数往往比程序员自己实现的同样功能的函数 更合理、更高效、更健壮,因为它们经受住了真实网络环境下的高压测试,以及时间的考验。下面我们以Reactor模式实现,基于Reactor模式的I/O框架库包含以下几个组件:句柄(描述符)、时间多路分发器、

1、句柄

     I/O框架要处理的对象,即I/O事件、信号和定时事件,统一称为事件源。一个事件源通常和一个句柄绑定在一起,句柄的作用:当内核检测到就绪事件时,它将通过句柄来通知应用程序这一事件。在Linux环境下,I/O事件对应的句柄就是文件描述符,信号事件对应的句柄就是信号值。

2、事件多路分发器

    事件的到来使随机的、异步的,我们无法预知程序何时收到一个客户连接请求,又亦或收到一个暂停信号。所以程序需要循环地等待并处理事件,这就是事件循环。在事件循环中,等待事件一般使用I/O复用技术来实现。I/O框架库一般将系统支持的各种I/O复用系统调用封装成统一的接口,称为事件多路分发器。事件多路分发器demultiplex方法是等待事件的核心函数,其内部调用的是select、poll、epoll_wait等函数

二、时间处理器和具体事件处理器

事件处理器执行事件对应的业务逻辑,它通常包含一个或多个handle_event回调函数,这些回调函数在事件循环中被执行。I/O框架提供的事件处理器通常是一个接口,用户需要继承它来实现自己的事件处理器,即具体事件处理器。因此,事件处理器中的回调函数一般被声明为虚函数,以支持用户的扩展。

小问号?事件处理器和句柄有什么关系?

当事件多路分发器检测到有事件发生时,它是通过描述符来通知应用程序的,因此,饿哦们必须将事件处理器和描述符绑定,才能在事件发生时获取到正确的事件处理器。

三、Reactor

    Reactor是I/O框架库的核心,它主要提供三个主要的方法:

(1)handle_events.该方法执行事件循环。它重复如下过程:等待事件,然后依次处理所有就绪事件对应的事件处理器。

(2)register_handler.该方法调用事件多路分发器的register_event方法来往事件多路分发器中注册事件

(3)remove_handler.该方法调用事件多路分发器的remove_event方法来删除事件多路分发器中的一个事件

  四、Libevent源码分析

Lievent具有以下的特点:

(1)跨平台支持,Lievent支持Linux、UNIX和Windows.

(2)统一事件源。Libevent对I/O事件、信号和定时事件提供统一的处理

(3)线程安全。Libevent使用libevent_pthreads库来提高线程安全支持

(4)基于Reactor模式的研究

代码实现:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <assert.h>
#include <signal.h>
#include <event.h>

void sig_cb(int fd, short ev, void* arg)
{
    printf("fd=%d\n",fd);
}
void timeout_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 = evsignal_new(base,SIGINT,sig_cb,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 = {3,0};  //创建定时事件处理器
    //struct event * time_ev = evtimer_new(base,timeout_cb,NULL);
    //struct event * time_ev = event_new(base,-1,EV_TIMEOUT|EV_PERSIST,timeout_cb,NULL);
    struct event * time_ev = event_new(base,-1,EV_TIMEOUT,timeout_cb,NULL);
    event_add(time_ev,&tv);
	//调用该函数来执行事件循环
    event_base_dispatch(base);

    //事件结束后,使用*_free系列函数来释放系统资源
    event_free(time_ev);
    event_free(sig_ev);
    event_base_free(base);

}

服务器代码实现:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <assert.h>
#include <signal.h>
#include <event.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>

#define  MAXFD   20

struct event* fds_map[MAXFD];
void fds_map_init(struct event* fds[] )
{
    int i = 0;
    for( ;i < MAXFD; i++ )
    {
        fds[i] = NULL;
    }
}

void fds_map_add(struct event * fds[], int fd, struct event* ev)
{
    if ( fd >= MAXFD || ev == NULL)
    {
        return ;
    }

    fds[fd] = ev;
}
struct event* fds_map_find(struct event * fds[], int fd)
{
    return fds[fd];
}
void fds_map_del(struct event * fds[], int fd )
{
    if ( fd >= MAXFD )
    {
        return;
    }
    fds[fd] = NULL;
}
void c_cb(int fd, short ev, void* arg)
{
    if ( ev & EV_READ )
    {
        char buff[128] = {0};
        if ( recv(fd,buff,127,0) <= 0 )
        {
            
            event_free(fds_map_find(fds_map,fd));
            fds_map_del(fds_map,fd);
            close(fd);
            printf("one client over\n");
            return;
        }
        printf("buff=%s\n",buff);
        send(fd,"ok",2,0);
    }
}
void accept_cb(int fd, short ev, void * arg)
{
    struct event_base * base = (struct event_base*)arg;
    struct sockaddr_in caddr;
    int len = sizeof(caddr);
    if ( ev & EV_READ )
    {
        int c = accept(fd,(struct sockaddr*)&caddr,&len);
        if ( c <0 )
        {
            return ;
        }

        struct event * ev_c = event_new(base,c,EV_READ|EV_PERSIST,c_cb,NULL);
        event_add(ev_c,NULL);
        fds_map_add(fds_map,c,ev_c);
    }
    
}
int main()
{
	//创建套接字
    int sockfd = socket(AF_INET,SOCK_STREAM,0);
    assert( sockfd != -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));
    assert( res != -1 );

    listen(sockfd,5);

    fds_map_init(fds_map);
	//调用event_init函数创建event_base对象,一个event_base相当于一个Reactor实例
    struct event_base * base = event_init();
    assert( base != NULL );
	//   event_new创建信号事件                         //事件触发之后,自动重新对这个event调用event_add函数(永久性事件)
    struct event* ev_sock = event_new(base,sockfd,EV_READ|EV_PERSIST,accept_cb,base);
                                                                //指定的回调函数
	//调用event_add函数,将事件处理器添加到注册事件队列中,并将该事件处理器对应的事件添加到事件多路分发器中   
	event_add(ev_sock,NULL);
    fds_map_add(fds_map,sockfd,ev_sock);
	//调用该函数来执行事件循环
    event_base_dispatch(base);
	//事件结束后,使用*_free系列函数来释放系统资源
    event_free(ev_sock);
    event_base_free(base);
     
}

五、Lievent支持的事件类型

猜你喜欢

转载自blog.csdn.net/YL970302/article/details/83582492
今日推荐