- Linux服务器程序处理的三类事件
- I/O框架库的组件
- Libevent支持的事件类型:
- 代码实现
- 客户端
- 服务器
I/O事件、信号事件和定时事件。
I/O框架库以库函数的形式,封装了较为底层的系统调用。
I/O框架库的组件基于Reactor模式的I/O框架库包含的组件:句柄、事件多路分发器、事件处理器和具体的事件处理器。
-
句柄
I/O框架库要处理的对象,即I/O事件、信号事件和定时事件,统一称为事件源。
I/O事件对应的句柄是文件描述符,信号事件对应的句柄是信号值。 -
事件多路分发器
即事件循环。内部调用的是select、poll、epoll_wait. -
事件处理器和具体事件处理器
- 定义实例;
- 创建事件;
- 注册(添加)到libevent;
- 事件循环;
1 #include2 #include 3 #include 4 #include 5 #include 6 #include 7 #include 8 9 void sig_cb(int fd,short ev,void*arg)//回调函数 10 { 11 printf("sig=%dn",fd); 12 } 13 void time_cb(int fd,short ev,void*arg) 14 { 15 printf("time outn"); 16 } 17 int main() 18 { 19 struct event_base*base=event_init();//定义一个实例(libevent) 框架 20 assert(base!=NULL); 21 22 struct event*sig_ev=evsignal_new(base,SIGINT,sig_cb,NULL); //定义信号事> 件 23 assert(sig_ev!=NULL); 24 25 event_add(sig_ev,NULL);//添加(注册)事件到libevent实例 26 27 struct timeval tv={5,0}; 28 struct event*time_ev=evtimer_new(base,time_cb,NULL);//定义定时事件 29 assert(time_ev!=NULL); 30 event_add(time_ev,&tv);//设置(添加)超时事件 31 32 event_base_dispatch(base); //启动事件循环 33 34 event_free(sig_ev); 35 event_free(time_ev); 36 event_base_free(base); 37 38 exit(0); 39 }
编译时,注意连接库,加上 -levent。
通过Libevent 检测多个客户端连接
自动调用I/O函数处理并发事件
#include服务器2 #include 3 #include 4 #include 5 #include 6 #include 7 #include 8 #include 9 10 int main() 11 { 12 int sockfd=socket(AF_INET,SOCK_STREAM,0);//创建套接字 13 assert(sockfd!=-1); 14 15 //bind()//可以绑定,但是一般不绑定 16 17 struct sockaddr_in saddr; 18 memset(&saddr,0,sizeof(saddr)); 19 saddr.sin_family=AF_INET; 20 saddr.sin_port=htons(6000); 21 saddr.sin_addr.s_addr=inet_addr("127.0.0.1"); 22 23 int res=connect(sockfd,(struct sockaddr*)&saddr,sizeof(saddr));//三次握手 24 assert(res!=-1); 25 while(1) 26 { 27 char buff[128]={0}; 28 printf("input:n"); 29 fgets(buff,128,stdin); 30 31 if(strncmp(buff,"end",3)==0) 32 { 33 break; 34 } 35 send(sockfd,buff,strlen(buff),0); 36 37 memset(buff,0,128); 38 recv(sockfd,buff,127,0); 39 printf("buff=%sn",buff); 40 } 41 close(sockfd); 42 }
1 #include2 #include 3 #include 4 #include 5 #include 6 #include 7 #include 8 #include 9 #include 10 11 void recv_cb(int fd,short ev,void*arg) 12 { 13 if(ev&EV_READ) 14 { 15 char buff[128]={0}; 16 int n=recv(fd,buff,127,0); 17 if(n<=0) 18 { 19 struct event**p_cev=(struct event**)arg; 20 event_free(*p_cev); 21 free(p_cev); 23 close(fd); 22 printf("cilent closen"); 23 return ; 24 } 25 printf("recv:%sn",buff); 26 27 send(fd,"ok",2,0);//写事件就绪,不用注册写事件,直接send 28 } 29 } 30 void accept_cb(int fd,short ev,void* arg) 31 { 32 struct event_base* base=(struct event_base*)arg; 33 if(base==NULL) 34 { 35 return ; 36 } 37 if(ev&EV_READ) 38 { 39 struct sockaddr_in caddr; 40 int len=sizeof(caddr); 41 int c=accept(fd,(struct sockaddr*)&caddr,&len);//接受连接 42 if(c<0) 43 { 44 return ; 45 } 46 printf("accept c=%dn",c); 47 struct event**p_cev=(struct event**)malloc(sizeof(struct event*)); 48 if(p_cev==NULL) 49 { 50 return ; 51 } 52 *p_cev=event_new(base,c,EV_READ|EV_PERSIST,recv_cb,p_cev);//将c添加到libevent实例中 53 // struct event*c_ev=event_new(base,c,EV_READ|EV_PERSIST,recv_cb,base); 54 55 if(*p_cev==NULL) 56 { 57 return ; 58 } 59 event_add(*p_cev,NULL); 60 } 61 62 } 63 64 int socket_init(); 65 int main() 66 { 67 struct event_base*base=event_init(); 68 assert(base!=NULL); 69 70 int sockfd=socket_init(); 71 assert(sockfd!=-1); 72 73 struct event*sock_ev=event_new(base,sockfd,EV_READ|EV_PERSIST,accept_cb,base); 74 event_add(sock_ev,NULL); 75 76 event_base_dispatch(base);//启动事件循环 77 event_free(sock_ev); 78 event_base_free(base); 79 } 80 81 int socket_init() 82 { 83 int sockfd=socket(AF_INET,SOCK_STREAM,0);//创建套接字 84 if(sockfd==-1) 85 { 86 return -1; 87 } 88 89 struct sockaddr_in saddr; 90 memset(&saddr,0,sizeof(saddr)); 91 saddr.sin_family=AF_INET; 92 saddr.sin_port=htons(6000); 93 saddr.sin_addr.s_addr=inet_addr("127.0.0.1"); 94 int res=bind(sockfd,(struct sockaddr*)&saddr,sizeof(saddr));//指定监听> 套接子使用的是本主机的端口 95 if(res==-1) 96 { 97 return -1; 98 } 99 100 res=listen(sockfd,5); 101 if(res==-1) 102 { 103 return -1; 104 } 105 return sockfd; 106 107 }



