libevent笔记-事件/事件循环

来源:互联网 发布:淘宝借贷逾期 编辑:程序博客网 时间:2024/04/19 19:24
//libevent笔记-事件/事件循环//转载请注明出处: yuliying的csdn博客.//===事件循环控制主要是开始事件循环和终止事件循环===//1.使用默认配置开始事件循环: event_base_dispatch()//2.开始事件循环,可以设置一些参数: event_base_loop()//3.指定时间后退出事件循环,处理完回调函数后退出 : event_base_loopexit()//4.立即退出事件循环: event_base_loopbreak()//===libevent的基本操作单元是事件(event),每个(event)都是下列情况发生的集合===//1.文件描述符【已经】可读/可写.//2.文件描述符【变为】可读/可写.(边缘触发模式下)//3.超时事件时间已到//4.进程收到信号//5.用户自己触发事件//===事件有几个状态===//1.已初始化状态(initialized). 设置好一个事件,并且将其关联到一个event_base.//2.等待状态(pending). 将上述已初始化状态的事件添加到event_base,事件变为待触发状态.//3.激活状态(active). 待触发事件的触发条件满足,事件变为触发状态.//===初始化事件(event_new)时,libevent可关注的事件有下列几种,可以是下列事件的组合===//1.EV_TIMEOUT : 超时事件.当在添加事件到循环(event_add)的时候设置一个超时时间.这个标记超时的时候在回调函数中的事件集合中被标记.//2.EV_READ : 文件描述符可读事件//3.EV_WRITE: 文件描述符可写事件//4.EV_SIGNAL: 进程信号事件//5.EV_PERSIST : 将当前事件标记为永久事件,非永久事件只能激活一次,回调函数执行后变为已始化状态.永久事件激活处理后后变为等待状态.//6.EV_ET : 该文件描述符事件使用边缘触发方式.//===文件描述符事件(通用事件)操作函数===//1.初始化事件: event_new()//2.添加事件到事件循环 : event_add()//3.从事件循环删除事件,不再监听:event_del()//4.销毁事件: event_free()//5.判断事件是否处于pending或者active状态,返回关注的事件或者激活的事件. event_pending()//6.设置事件的优先级: event_priority_set()//7.获取事件对应的文件描述符: event_get_fd()//8.从事件获取event_base : event_get_base()//9.获取关注的事件: event_get_events()//10.获取事件的回调函数: event_get_callback()//11.获取事件回调函数的参数: event_get_callback_arg()//12.获取事件的优先级: event_get_priority()//13.手动激活事件: event_active()//===单纯的定时器事件操作函数(通用函数的包装的宏,方便使用)===//1.初始化事件: evtimer_new()//2.添加事件到事件循环 : evtimer_add()//3.从事件循环删除事件,不再监听: evtimer_del()//4.销毁事件: evtimer_del()//5.判断事件是否处于pending或者active状态,返回关注的事件或者激活的事件. evtimer_pending()//===单纯的信号事件操作函数(通用函数的包装的宏,方便使用)===//1.初始化事件: evsignal_new()//2.添加事件到事件循环 : evsignal_add()//3.从事件循环删除事件,不再监听: evsignal_del()//4.销毁事件: event_free()//5.判断事件是否处于pending或者active状态,返回关注的事件或者激活的事件. evsignal_pending()//下面代码分别演示:文件描述符事件/超时事件/信号事件.#include <event2/event.h>#include <fcntl.h>#include <string.h>#include <errno.h>#include <signal.h>//保存所有fd对应的event结构体指针.方便销毁事件.//一些事件的销毁这里就不做处理了.实际程序中注意内存泄露.当事件已经无用后记得销毁掉.struct event * fdevent_array[10000];void setnonblock(int fd){    int flags = fcntl(fd, F_GETFL);    fcntl(fd, F_SETFL, flags | O_NONBLOCK);}void reuseAddr(int fd) {    int yes = 1;    setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes));}void read_cb(evutil_socket_t fd, short events, void *arg){struct event * myevent;if ( events & EV_READ ){//真正的应用中这里需要两个用户的buffer来保存该连接上的数据.char buffer[1024];while(1){memset( buffer , 0 , 1024);int nbytes = read( fd , buffer , 1023);if ( nbytes < 0){if (errno == EINTR) continue;if (errno == EAGAIN) break;printf("client error , fd [%d]\n" , fd);goto fdclose;break;}if ( nbytes == 0){printf("client close , fd [%d]\n" , fd);goto fdclose;break;}printf("data from client: %s" , buffer);write( fd , buffer , nbytes);}}return;fdclose://myevent = fdevent_array[fd];event_del(myevent);event_free(myevent);close(fd);fdevent_array[fd] = NULL;}void listen_cb(evutil_socket_t listener, short events , void *arg){if (events & EV_TIMEOUT ){printf("timer event\n");}if (events & EV_READ ){struct event_base *base = arg;struct sockaddr_storage ss;socklen_t slen = sizeof(ss);int fd = accept(listener, (struct sockaddr*)&ss, &slen);//接受了一个新客户连接,我们为这个新连接设置一个事件if(fd > 0){printf("accept new client fd [%d]\n" , fd);setnonblock( fd );//我们现在只关注读事件,将客户端发来的信息回送给客户端.struct event * client_event = event_new( base , fd , EV_READ|EV_PERSIST , read_cb , (void*)base  );event_add( client_event , NULL);fdevent_array[fd] = client_event;}}}void sigint_cb(evutil_socket_t sig, short events , void *arg){struct event_base *base = arg;if ( events & EV_SIGNAL ){printf("capture signal [%d]\n" , sig);event_base_loopbreak(base);}}int main(){//struct event_base * base = event_base_new();//以下代码开启server监听一个本地端口.可以将ip改为自己的服务器以方便测试.int port = 9999;struct sockaddr_in my_addr;memset( &my_addr , 0 , sizeof(struct sockaddr_in));my_addr.sin_family=AF_INET;my_addr.sin_port=htons(port);my_addr.sin_addr.s_addr=inet_addr("127.0.0.1");int listen_socket = socket(AF_INET , SOCK_STREAM , 0);setnonblock(listen_socket);reuseAddr(listen_socket);bind(listen_socket , (struct sockaddr*)&my_addr , sizeof(struct sockaddr));listen(listen_socket , 10);//给监听的socket添加一个事件,用来accept新连接,关注读事件,并将该event设置为永久事件.设置好回调函数和参数.struct event *listener_event = event_new( base , listen_socket , EV_READ|EV_PERSIST , listen_cb , (void*)base);//将监听事件加入事件循环.同时我们在监听事件上加一个定时器事件.在回调函数中判断应该接受连接还是定时器触发.struct timeval expire = { 5 , 0 };event_add( listener_event , &expire);fdevent_array[listen_socket] = listener_event;//设置一个信号事件,我们监听(ctrl+c的中断信号),收到信号后打印一条消息,退出事件循环.struct event *signal_event = evsignal_new( base , SIGINT , sigint_cb , (void*)base);evsignal_add( signal_event , NULL );//开始事件循环event_base_dispatch( base );//event_base_free(base);}

0 0
原创粉丝点击