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)
- Libevent监听事件的建立过程
- 建立自己的libevent工程
- libevent(三)事件注册与循环监听
- 试用libevent的事件触发
- libevent 事件的优先级队列
- libevent之事件的创立
- LibEvent的使用过程记录
- libevent代码阅读(13)——epoll的事件等待以及分发过程
- [Servlet]事件监听,ServletContext的事件监听
- [Servlet]事件监听,ServletContext的事件监听
- libevent源码分析--libevent库对信号事件的处理
- JTree的事件监听
- JTabbedPane的事件监听
- combobox的监听事件
- Hibernate的事件监听
- EditText的监听事件
- UIMenuController的事件监听
- 监听事件的使用
- JAVA基础--JAVA中的反射机制详解
- date_default_timezone_set()问题解决方案(PHP5.3以上的)
- 许多实用的JS 正则表达式
- Eclipse中如何搜索整个工程
- TreePanel的各项属性
- Libevent监听事件的建立过程
- jeecms 配置可以低级别用户流程
- [MySQL登录错误] ERROR1045 (28000): Access denied for user 'omonroy'@'20.112.251.19' (using password:YES)
- OpenCV 实现颜色直方图
- OS开发之----常用函数和常数
- Oracle GoldenGate安装配置教程
- c++类成员函数作为回调函数
- Winrt 环境自定义 API 与系统 API 冲突解决
- 新的开始