Libevent监听事件的建立过程

来源:互联网 发布:乌合之众 知乎 版本 编辑:程序博客网 时间:2024/06/06 02:19

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




几个重要的结构体

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 intevent_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 inlineint 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 voidlistener_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)


原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 手机一体机死机关不了机怎么办 联想一体机关不了机怎么办 纸巾盒的吸盘老化了怎么办 粘的挂钩老掉怎么办 车载手机支架吸盘吸不住怎么办 吸盘吸不住怎么办才好? 行车记录仪吸盘吸不住怎么办 小米儿童手表二维码丢了怎么办 艾蔻手表二维码丢失了怎么办 玩具直升机遥控器坏了怎么办 玩具飞机遥控器坏了怎么办 玩具无人机遥控器坏了怎么办 玩具遥控车遥控器坏了怎么办 用遥控器关电视后打不开怎么办 汽车遥控器按键坏了怎么办 用遥控器关了电视打不开怎么办 遥控器一个按键坏了怎么办 电视用遥控器关的打不开怎么办 电动车遥控器按键坏了怎么办 海尔空调遥控器按键坏了怎么办 汽车手机支架吸盘吸不住怎么办 车载手机支架吸盘坏了怎么办 假牙的吸盘坏了怎么办 燃气费用一直未交怎么办 凌度gps模块无法定位怎么办? 放疗定位线掉了怎么办 被网络平台骗了怎么办 手机重力传感器坏了怎么办 锤子手机重力传感器坏了怎么办 平板电脑没有开关键怎么办 手机重力感应器坏了怎么办 苹果手机重力感应器坏了怎么办 苹果手机陀螺仪坏了怎么办 狗狗的爪子肿了怎么办 压缩文件之后显示拒绝访问怎么办 压缩文件解压后全散开了怎么办 dnf助手改名字用完了怎么办 缅甸 佤邦 办中国护照 怎么办? 电脑玩游戏网络延迟大怎么办 qq好友空间锁了怎么办 卡盟进货额不足怎么办