使用libevent创建服务

libevent的使用过程比较简单,就是创建一个监听事件,包含fd,事件回调等参数,然后添加到libevent事件里面,调用libevent

事件调度函数loop起来。看下面的例子

using namespce std;
#define SERVER_ADDR "127.0.0.1"
#define SERVER_PORT 8888

//事件base
struct event_base* base;
//读事件回调函数
void onRead(int iCliFd,short iEvent,void *arg)
{
    int iLen;
    char buf[1500];
    iLen recv(iCliFd,buf,1500,0);
    if(iLen <= 0)
    {
        cout <<"Client Close"
    
        struct event *pEvRead = (struct event*)arg;
        event_del(pEvRead);
        delete pEvRead;
        close(iCliFd);
        return ;
    }
    buf[iLen] = 0;
    cout << "Client Info:" << buf << endl;

    struct bufferevent* buf_ev;

    buf_ev = bufferevent_new(iCliFd, NULL, NULL, NULL, NULL);// 创建一个新的事件

/*

每个 bufferevent 有四个水位:
        读取低水位 : 读取操作使得输入缓冲区的数据量在此级别或者更高时 ,读取回调将被调用。默认值为 0,所以每个读取操作都会导致读取回调被调用。
        读取高水位 : 输入缓冲区中的数据量达到此级别后, bufferevent 将停止读取,直到输入缓冲区中足够量的数据被抽取 ,使得数据量低于此级别 。默认值是无限 ,所以永远不会因为输入缓冲区的大小而停止读取。
        写入低水位 : 写入操作使得输出缓冲区的数据量达到或者低于此级别时 ,写入回调将被调用。默认值是 0,所以只有输出缓冲区空的时候才会调用写入回调。
        写入高水位 : bufferevent 没有直接使用这个水位。它在 bufferevent 用作另外一 个 bufferevent 的底层传输端口时有特殊意义。

*/

    char MESSAGE[]="welcome to server..";

    bufferevent_write(buf_ev, MESSAGE, strlen(MESSAGE));    
    
}

//连接请求事件回调函数

void onAccept(int iSvrFd,short iEvent,void *arg)//Listen回调函数
{// Listen事件也是监听的读事件,
    int iCliFd;
    struct  sockaddr_in sCliAddr;
    socklen_t iSinSize = sizeof(sCliAddr);
    iCliFd = accept(iSvrFd,(struct sockaddr*)&sCliAddr,&iSinSize);
    //链接注册为新事件(EV_PERSIST 为事件触发后不默认删除)
    struct event* pEvRead = new event;
    event_set(pEvRead, iCliFd, EV_READ|EV_PERSIST, onRead, pEvRead);
    event_base_set(base,pEvRead);
    event_add(pEvRead,NULL);
    struct bufferevent* buf_ev;
    buf_ev = bufferevent_new(iCliFd,NULL,NULL,NULL,NULL);
    char MESSAGE[]="welcome to server..";

 

//这里看一下读取水位的作用,

/*

buf_ev->wm_read.high = 4096; // 如果本地应用层buffer比4096小,就不读取了。原因是每次读取都是按4096为单位读取的

static void bufferevent_inbuf_wm_check(struct bufferevent *bev)
{
    if (!bev->wm_read.high)
        return;
    if (!(bev->enabled & EV_READ))
        return;
    if (evbuffer_get_length(bev->input) < bev->wm_read.high)
        return;

    bufferevent_trigger(bev, EV_READ, BEV_OPT_DEFER_CALLBACKS);
}

*/

 

    bufferevent_write(buf_ev, MESSAGE, strlen(MESSAGE));//监听到事件后,

    cout<<"a client connect:"<<iclifd<<endl;< p="">
}

int main()
{
    int iSvrFd;
    struct sockaddr_in sSvrAddr;
    memset(&sSvrAddr,0,sizeof(sSvrAddr));
    sSvrAddr.sin_family = AF_INET;
    sSvrAddr.sin_addr.s_addr = inet_addr(SERVER_ADDR);
    sSvrAddr.sin_port = htons(SERVER_PORT);
    
    iSvrFd = socket(AF_INET,SOCK_STREAM,0);
    bind(iSvrFd,(struct sockaddr*)&sSvrAddr,sizeof(sSvrAddr));
    listen(iSvrFd,10);
    //初始化base
    base = (struct event_base*)event_init();
    struct event evListen;
    //设置事件
    event_set(&evListen, iSvrFd, EV_READ|EV_PERSIST, onAccept, NULL);

/*

默认情况下,任何时候一个挂起的事件被激活(因为他的fd准备好了读或者写,或者因为他的超时过期了),它会在回调函数执行之前变为非挂起。如果你想让事件再次挂起,你需要在回调函数内部调用event_add()
如果一个事件被设置了EV_PERSIST,那么这个事件就是持续化的,意思就是这个事件会保持挂起状态,即使回调函数被执行。如果你想让它变为非挂起状态,可以在回调函数中调用event_del()

任何时候事件的回调函数触发都会重置持续化事件中的超时状态。因此,如果的事件有EV_READ/EV_PERSIST并且设置了5秒超时,那么有两种情况会触发这个事件:

  1. 当socket可以进行读取的时候

  2. 当5s超时到期的时

*/
    //设置为base 事件base
    event_base_set(base,&evListn);
    //添加事件
    event_add(&evListen,NULL);// 每个event 添加都有一个超时参数,

//如果不设置就是默认的超时参数
    //添加事件
    event_base_dispatch(base);//主循环LOOP

    return 0;
}

//libevent内部超时事件实现

static void
timeout_process(struct event_base *base)
{
    /* Caller must hold lock. */
    struct timeval now;
    struct event *ev;

    if (min_heap_empty_(&base->timeheap)) {
        return;
    }

    gettime(base, &now);

    while ((ev = min_heap_top_(&base->timeheap))) { // 最小堆弹出,

//这里的定时器是一个小根堆结构
        if (evutil_timercmp(&ev->ev_timeout, &now, >))
            break;

        /* delete this event from the I/O queues */
        event_del_nolock_(ev, EVENT_DEL_NOBLOCK);

        event_debug(("timeout_process: event: %p, call %p",
             ev, ev->ev_callback));
        event_active_nolock_(ev, EV_TIMEOUT, 1);
    }
}

 

event_base_dispatch()-->timeout_process()

-->堆定时器处理。

epoll事件激活

const struct eventop epollops = {
    "epoll",
    epoll_init,
    epoll_nochangelist_add,
    epoll_nochangelist_del,
    epoll_dispatch,
    epoll_dealloc,
    1, /* need reinit */
    EV_FEATURE_ET|EV_FEATURE_O1|EV_FEATURE_EARLY_CLOSE,
    0
};

res = evsel->dispatch(base, tv_p);

epoll_dispatch(struct event_base *base, struct timeval *tv)
{

      res = epoll_wait(epollop->epfd, events, epollop->nevents, timeout);

     //激活事件

for (i = 0; i < res; i++) {
        int what = events[i].events;
        short ev = 0;
#ifdef USING_TIMERFD
        if (events[i].data.fd == epollop->timerfd)
            continue;
#endif

        if (what & (EPOLLHUP|EPOLLERR)) {
            ev = EV_READ | EV_WRITE;
        } else {
            if (what & EPOLLIN)
                ev |= EV_READ;
            if (what & EPOLLOUT)
                ev |= EV_WRITE;
            if (what & EPOLLRDHUP)
                ev |= EV_CLOSED;
        }

        if (!ev)
            continue;

        evmap_io_active_(base, events[i].data.fd, ev | EV_ET);
    }

}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值