Libevent监听事件的建立过程

事件建立和触发机制如下图所示:




几个重要的结构体

struct evconnlistener_ops

{

         int(*enable)(struct evconnlistener *);

         int(*disable)(struct evconnlistener *);

         void(*destroy)(struct evconnlistener *);

         void(*shutdown)(struct evconnlistener *);

         evutil_socket_t (*getfd)(struct evconnlistener *);

         structevent_base *(*getbase)(struct evconnlistener*);

};

该结构体内保存了常用方法的函数指针。

struct evconnlistener

{

         const struct evconnlistener_ops *ops;

         void*lock;

         evconnlistener_cb cb;

         evconnlistener_errorcb errorcb;

         void*user_data;

         unsignedflags;

         shortrefcnt;

         unsignedenabled : 1;

};

该结构体内是监听结构体,保存了回调函数指针,用户数据等常用参数。

struct evconnlistener_event

{

         structevconnlistener base;

         struct event listener;

}

该结构体是对监听结构体的再次封装,将监听结构体和事件结构体关联起来。

 

在主程序中一般调用如下方法得到监听结构体,并设置回调函数。           

struct event_base *base;

struct evconnlistener *listener;

struct sockaddr_in sin;

base =event_base_new();

memset(&sin, 0, sizeof(sin));

sin.sin_family =AF_INET;

sin.sin_port =htons(PORT);

listener =evconnlistener_new_bind(base, listener_cb, (void*)base,LEV_OPT_REUSEABLE, -1,(structsockaddr*)&sin,sizeof(sin));       

 

struct evconnlistener *

evconnlistener_new_bind(struct event_base *base, evconnlistener_cb cb,void *ptr, unsignedflags, int backlog, conststruct sockaddr *sa,intsocklen)

{

   //建立套接字,设置套接字参数,端口绑定

   //建立实际的evconnlistener结构体

   listener = evconnlistener_new(base, cb, ptr,flags, backlog, fd);

   返回监听结构体

}

 

struct evconnlistener *evconnlistener_new(struct event_base *base,evconnlistener_cb cb, void *ptr, unsignedflags, int backlog,evutil_socket_t fd)

{

 

//在建立好的套接字上启动监听

//创建evconnlistener_event结构体,在该结构体内部的evconnlistener结构体上设置回调函数和相关参数。

//设置evconnlistener_event结构体内的event结构体(lev->listener)属性。

event_assign(&lev->listener,base, fd, EV_READ|EV_PERSIST,listener_read_cb, lev);

 

//将该监听事件增加到监听队列中

evconnlistener_enable(&lev->base);

 

}

 

int  event_assign(structevent *ev, structevent_base *base, evutil_socket_t fd, shortevents, void (*callback)(evutil_socket_t, short, void *), void *arg)

{

  //设置回调函数,此回调函数非最开始设置的回调函数,套接字、事件类型等参数

}

 

int  evconnlistener_enable(struct evconnlistener *lev)

{

  调用evconnlistener_ops结构体体的enable静态方法,实际是下面的方法 

}

static int event_listener_enable(struct evconnlistener *lev)

{

     首先进行地址转换,得到evconnlistener_event地址指针

         structevconnlistener_event *lev_e =EVUTIL_UPCAST(lev, structevconnlistener_event, base);

    //事先事件增加,内部调用event_add_internal

         returnevent_add(&lev_e->listener, NULL);

}

static inline int event_add_internal(structevent *ev, conststruct timeval *tv,inttv_is_absolute)

{

  //将事件增加到哈希表中,并将该事件的fd增加到底层监听数组中。

 res = evmap_io_add(base,ev->ev_fd, ev);

 //将该事件增加到base的 eventqueue列表中

 event_queue_insert(base, ev,EVLIST_INSERTED);

}

到此处监听事件已经增加完毕,底层开始监听:

event_base_dispatch(base);

 

在下面的函数内进行事件监听

win32_dispatch(struct event_base *base, structtimeval *tv)

{

//监听事件

res =select(fd_count,

                        (structfd_set*)win32op->readset_out,

                        (structfd_set*)win32op->writeset_out,

                        (structfd_set*)win32op->exset_out, tv);

//激活事件

evmap_io_active(base,s, EV_READ);

 

}

 

evmap_io_active(struct event_base *base, evutil_socket_t fd, short events)

{

   //得到该fd下的evmap_io对象

    //对所有的fd下的事件进行激活

         TAILQ_FOREACH(ev, &ctx->events,ev_io_next)

     {

                   if(ev->ev_events & events)

         {

                            event_active_nolock(ev,ev->ev_events & events, 1);

         }

     }

 

}

 

void event_active_nolock(structevent *ev, intres, short ncalls)

{

   //经过一系列判断后是调用如下函数,将该事件增加到event_base的激活队列中

   event_queue_insert(base, ev, EVLIST_ACTIVE);

 

}

 

int event_base_loop(structevent_base *base, int flags)

{

   //处理激活事件,该函数内部调用event_process_active_single_queue(base, activeq);

   event_process_active(base);

 

}

static int

event_process_active_single_queue(struct event_base *base, structevent_list *activeq)

{

  //从激活队列里删除

  event_queue_remove(base, ev, EVLIST_ACTIVE);

  //在如下函数内调用listener_read_cb(evutil_socket_tfd, short what, void*p)回调函数

  event_persist_closure(base, ev);

}

 

 

static void listener_read_cb(evutil_socket_tfd, short what, void*p)

{

//创建通讯套接字

 evutil_socket_t new_fd = accept(fd, (struct sockaddr*)&ss, &socklen);

 调用我们自己的监听回调函数

}

到此处一个完整的监听过程就结束了

static voidlistener_cb(struct evconnlistener *listener,evutil_socket_t fd,struct sockaddr *sa, int socklen, void*user_data)


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值