libevent 编程流程
libevent 是一个基于reactor的模型,本事是个同步的,底层封装了select/epoll ,通过循环检测,如果有就绪事件,通知处理函数处理。
libevent 编程逻辑
- 调用event_init 创建event_base,一个event_base 相当于一个reactor实例
- 然后给这个实例创建具体的注册方法:
// 创建新事件 struct event *event_new( struct event_base *base, // reactor 实例 evutil_socket_t fd, - // 文件描述符 - int **底层是对epollin与epollout的封装** short what, event_callback_fn cb, // 事件的处理回调函数 void *arg //回调函数传参 );
short what 事件标志:
EV_TIMEOUT 这个标志表示某超时时间流逝后事件成为激活的。构造事件的时候,EV_TIMEOUT 标志是 被忽略的:可以在添加事件的时候设置超时,也可以不设置。超时发生时,回调函数的 what 参数将带有这个标志。 EV_READ 表示指定的文件描述符已经就绪,可以读取的时候,事件将成为激活的。 EV_WRITE 表示指定的文件描述符已经就绪,可以写入的时候,事件将成为激活的。 EV_SIGNAL 用于实现信号检测,请看下面的“构造信号事件”节。 EV_PERSIST 表示事件是“持久的”,请看下面的“关于事件持久性”节。 EV_ET 表示如果底层的 event_base 后端支持边沿触发事件,则事件应该是边沿触发的。这个标志 影响 EV_READ 和 EV_WRITE 的语义。 - event_add()将事件添加到event_base 上
// event_add int event_add( struct event *ev, const struct timeval *tv );
- tv:参数 Value NULL: 事件被触发, 对应的回调被调用 tv = {0, n} 设置的时间,在改时间段内检测的事件没被触发, 时间到达之后, 回调函数还是会被调用
-
使用event_base_dispatch()函数 事件循环
- 释放资源
// 创建event_free void event_free(struct event *event); // 释放event_base_free event_base_free(struct event_base* base);
一个http使用libevent:
#include<stdio.h> #include<stdlib.h> #include<string.h> #include<unistd.h> #include<assert.h> #include<sys/socket.h> #include<netinet/in.h> #include<arpa/inet.h> #include<event.h> #include<fcntl.h> #define PATH "/home/liuchen/" #define MAX 100 struct event* map_arr[MAX]; void Map_arr_init() { int i=0; for(;i<MAX;i++) { map_arr[i]=NULL; } } void Map_arr_add(int fd,struct event* ev) { if(fd<0||fd>MAX) { return; } map_arr[fd]=ev; } struct event* Map_arr_find(int fd) { if(fd<0||fd>MAX) { return NULL; } return map_arr[fd]; } int Sockfd_create() { int sockfd=socket(AF_INET,SOCK_STREAM,0); if(sockfd==-1) { return -1; } struct sockaddr_in saddr; memset(&saddr,0,sizeof(saddr)); saddr.sin_family = AF_INET; saddr.sin_port = htons(80); saddr.sin_addr.s_addr = inet_addr("0.0.0.0"); int res=bind(sockfd,(struct sockaddr*)&saddr,sizeof(saddr)); if(res==-1) { return -1; } if(listen(sockfd,5)) { return -1; } return sockfd; } void Recv_cb(int fd,short ev,void *arg) { struct sockaddr_in * caddr = (struct sockaddr_in*)arg; if(ev & EV_READ) { char buff[1024]={0}; int n=recv(fd,buff,1023,0); if(n<=0) { event_free(Map_arr_find(fd)); map_arr[fd]=NULL; close(fd); printf("one client over id=%s port=%d",inet_ntoa(caddr->sin_addr),ntohs(caddr->sin_port)); return; } char *pname=NULL; pname=strtok(buff," "); if(pname==NULL) { event_free(Map_arr_find(fd)); map_arr[fd]=NULL; close(fd); return; } printf("Method:%s\n",pname); char *filename=strtok(NULL," "); if(filename==NULL) { event_free(Map_arr_find(fd)); map_arr[fd]=NULL; close(fd); return; } char path[128]={PATH}; if ( strcmp(filename,"/") == 0 ) { strcat(path,"/index.html"); } else { strcat(path,filename); } int xd = open(path,O_RDONLY); if(xd==-1) { event_free(Map_arr_find(fd)); map_arr[fd]=NULL; close(fd); return; } int filesize = lseek(xd,0,SEEK_END); lseek(xd,0,SEEK_SET); char head_buff[256] = {"HTTP/1.1 200 OK\r\n"}; strcat(head_buff,"Server: myhttp\r\n"); sprintf(head_buff+strlen(head_buff),"Content-Length: %d\r\n",filesize); strcat(head_buff,"\r\n"); printf("send:\n%s\n",head_buff); send(fd,head_buff,strlen(head_buff),0); char data[512] = {0}; int num = 0; while( (num = read(xd,data,512)) > 0 ) { send(fd,data,num,0); } } } void accept_cb(int fd,short ev,void *arg) { struct event_base * base=(struct event_base*)arg; if(ev & EV_READ) { struct sockaddr_in caddr; socklen_t len=sizeof(caddr); int c=accept(fd,(struct sockaddr*)&caddr,&len); if(c<0) { return; } struct event* ev_c = event_new(base,c,EV_READ | EV_PERSIST,Recv_cb,&caddr); event_add(ev_c,NULL); Map_arr_add(c,ev_c); } } int main() { Map_arr_init(); int sockfd=Sockfd_create(); assert(sockfd!=-1); struct event_base * base=event_base_new(); assert(base!=NULL); struct event* sock_ev = event_new(base,sockfd,EV_READ | EV_PERSIST,accept_cb,(void *)base); event_add(sock_ev,NULL); event_base_dispatch(base); event_free(sock_ev); event_base_free(base); }

浙公网安备 33010602011771号