libevent学习笔记一:总体把握
来源:互联网 发布:淘宝的延长收货是什么 编辑:程序博客网 时间:2024/05/22 08:11
分析libevent
- 如何使用 (官方手册,心得体会)
- 源码分析 (event, event_base 为核心)
引言
- 标准c库便有许多参用了回调函数,让用户制定处理过程,比如常用的 qsort(3), bsearch(3)
- 基本的socket编程时阻塞/同步的,线程在默认情况下占2~8M栈空间。posix的select(2)采用了轮循的方法来判断某个fd是否激活?故时间需要O(n),效率并不高
- 进而各个系统提出了异步的callback系统调用。 比如: linux的epoll(2),BSD 的kqueue(2),Windows的IOCP。 进而能够用 O(1)效率查找到激活的fd
libevent就是对这些高效IO的封装,提供统一的API,便于开发。
libevent默认为单线程,可以配置为多线程。
一个线程一个event_base,对应一个 struct event_base 和时间管理器,用 schedule 托管给它一系列的event。
当时间发生后,event_base 会在合适的时间(不一定立即)调用绑定于该事件的函数,直到函数运行完,再返回schedule其余事件。
struct event_base *base = event_base_new();assert(base != NULL);
event_base 内部阻塞于 epoll / kqueue
每个事件对应一个 struct event ,可以是监听一个 fd / posix 信号量
struct event 使用 event_new 创建绑定, event_add 来启用
补充下epoll的两个触发模式
- Edge Trigger 边缘触发: 状态变化时产生 IO 事件
- Level Trigger 水平(条件)触发: 满足条件就产生 IO 事件
对于server而言,大致过程如下:
- listener = socket() bind() listen() 设置fd为非阻塞non-blocking(fcntl(2)) 或者用libevent封装的evutil_make_socket_nonblocking
- 创建一个 event_base
- event_init() event_set() : 创建一个 event , 将该 socket 托管给event_base , 指定监听类型,绑定相应的回调函数和参数。 对于 listener socket 而言,只需要监听 EV_READ | EV_PERSIST , PERSIST是保持存在的选项
- event_add() : 添加该事件,设置超时时间
- event_dispatch() : 进入事件循环
- (异步) 当有client发起请求 / 事件发生,便会调用该回调函数进行处理
WHY ? 为何不在listen()之后立即调用 accept() ?
如果accept 获得和client通信的sockfd之后,马上进行 recv() / send() , 线程就会阻塞于此。
因此应该创建一个event来托管这个sockfd。
缓冲区管理 bufferevent
从libevent2开始,提供了bufferevent
struct bufferevent 内建立了两个event(read / write)和对应的缓冲区:
- struct evbuffer *input;
- struct evbuffer *output;
当有数据被读入 input 时,read_cb 立刻调用
当output被输出完毕的时候,write_cb 立刻调用
基本库
* I/O 事件 *
void get_time(int fd, short event, struct event *arg){ localtime_r(&now, &t); asctime_r(&t, buf); write(fd, buf, strlen(buf)); //get system time, then write it}void connect_accept(int fd, short event, void *arg){ //offer a callback function to the event, accept a connection struct sockaddr_in socket_in; socklen_t len = sizeof(socket_in); int accept_fd = accept(fd, (struct sockaddr *) &socket_in, &len); struct event *ev = (struct event *)malloc(sizeof(struct event)); event_set(ev, accept_fd, EV_WRITE, (void *)get_time, ev); event_add(ev, NULL);}int main(void){ int sockfd = socket(AF_INET, SOCK_STREAM, 0); struct sockaddr_in socket_in; bind(sockfd, (struct sockaddr *)&socket_in, sizeof(socket_in)); listen(sockfd, 5); event_init(); //libevent initialization struct event ev; // 设置事件为可读,持续,监听的是sockfd,回调函数connect_accept event_set(&ev, sockfd, EV_READ|EV_PERSIST, connect_accept, &ev); //添加事件,未设置超时时间 event_add(&ev, NULL); //进入libevent主循环,等待事件发生 event_dispatch(); return 0;}
信号处理事件
static void signal_cb(int fd, short event, void *arg){ struct event *signal = arg; printf("%s: got signal %d\n", __func__, EVENT_SIGNAL(signal)); // __func__ 是调用的函数名 if (called >= 2) event_del(signal); called++;}int main (int argc, char **argv){ struct event signal_int; event_init(); //libevent initialization event_set(&signal_int, SIGINT, EV_SIGNAL|EV_PERSIST, signal_cb, &signal_int); //设置事件属性为信号触发、持续,回调函数为con_accept() event_add(&signal_int, NULL); //添加事件 event_dispatch();//进入libevent主循环 return 0;}
常规超时处理
static void timeout_catch(int fd, short event, void *arg){ struct timeval tv; struct event *timeout = arg; int newtime = time(NULL); printf("%s : called at %d\n", __func__, newtime - lasttime); lasttime = newtime; evutil_timerclear(&tv); tv.tv_sec = 1; event_add(timeout, &tv);}int main(void){ struct event timeout; struct timeval tv; event_init(); evtimer_set(&timeout, timeout_catch, &timeout); //等价于 event_set(timeout, -1, 0, timeout_catch, &timeout); evutil_timerclear(&tv); tv.tv_sec = 1; event_add(&timeout, &tv); lasttime = time(NULL); event_dispath(); //enter the loop return 0;}
0 0
- libevent学习笔记一:总体把握
- libevent 学习笔记 一
- libevent 学习笔记 一
- libevent学习笔记 一、基础知识
- libevent学习笔记 一、基础知识
- libevent学习笔记 一、基础知识
- jquery源码学习笔记一:总体结构
- libevent源码解读(一)--总体阅读
- Libevent学习笔记一:异步IO
- Libevent学习笔记(一):基本使用
- 程序员的总体把握
- jvm虚拟机学习笔记(一)---总体认识
- libevent学习一
- Libevent源代码分析笔记一,初见libevent
- libevent学习笔记
- Libevent库学习笔记
- 学习笔记--libevent min_heap
- libevent学习笔记
- C++ 中dynamic_cast<>的使用方法
- 跨系统如何保持Session存活和Token共享问题
- python 之queue
- 【原】如何阅读学术论文
- 大型网站架构之系列
- libevent学习笔记一:总体把握
- 计算机计算乘除法的原理
- springMVC --DispatcherServlet详解
- iOS—修改AFNetworking源文件可接收text/plain的方法
- 树莓派 raspberry安全关机命令重启命令
- AppStore App申请审核加速
- MFC右键弹出菜单,并添加响应函数
- IOS- 得到系统版本
- 机器学习算法需要注意的一些问题