epoll服务器

来源:互联网 发布:excel学生成绩管理数据 编辑:程序博客网 时间:2024/05/21 09:45

下面来看看linux内核具体的epoll机制实现思路。

当某一进程调用epoll_create方法时,Linux内核会创建一个eventpoll结构体,这个结构体中有两个成员与epoll的使用方式密切相关。eventpoll结构体如下所示:

[cpp] view plain copy
  1. struct eventpoll{  
  2.     ....  
  3.     /*红黑树的根节点,这颗树中存储着所有添加到epoll中的需要监控的事件*/  
  4.     struct rb_root  rbr;  
  5.     /*双链表中则存放着将要通过epoll_wait返回给用户的满足条件的事件*/  
  6.     struct list_head rdlist;  
  7.     ....  
  8. };  

每一个epoll对象都有一个独立的eventpoll结构体,用于存放通过epoll_ctl方法向epoll对象中添加进来的事件。这些事件都会挂载在红黑树中,如此,重复添加的事件就可以通过红黑树而高效的识别出来(红黑树的插入时间效率是lgn,其中n为树的高度)。

而所有添加到epoll中的事件都会与设备(网卡)驱动程序建立回调关系,也就是说,当相应的事件发生时会调用这个回调方法。这个回调方法在内核中叫ep_poll_callback,它会将发生的事件添加到rdlist双链表中。

在epoll中,对于每一个事件,都会建立一个epitem结构体,如下所示:

[cpp] view plain copy
  1. struct epitem{  
  2.     struct rb_node  rbn;//红黑树节点  
  3.     struct list_head    rdllink;//双向链表节点  
  4.     struct epoll_filefd  ffd;  //事件句柄信息  
  5.     struct eventpoll *ep;    //指向其所属的eventpoll对象  
  6.     struct epoll_event event; //期待发生的事件类型  
  7. }  

当调用epoll_wait检查是否有事件发生时,只需要检查eventpoll对象中的rdlist双链表中是否有epitem元素即可。如果rdlist不为空,则把发生的事件复制到用户态,同时将事件数量返回给用户。

epoll.jpg

epoll数据结构示意图

从上面的讲解可知:通过红黑树和双链表数据结构,并结合回调机制,造就了epoll的高效。

OK,讲解完了Epoll的机理,我们便能很容易掌握epoll的用法了。一句话描述就是:三步曲。

第一步:epoll_create()系统调用。此调用返回一个句柄,之后所有的使用都依靠这个句柄来标识。

第二步:epoll_ctl()系统调用。通过此调用向epoll对象中添加、删除、修改感兴趣的事件,返回0标识成功,返回-1表示失败。

第三部:epoll_wait()系统调用。通过此调用收集收集在epoll监控中已经发生的事件。

epoll优点:
1.epoll维护的描述符数目不受到限制,而且性能不会随着描述符数目的增加而下降。(不需要遍历整个文件描述符)
2.epoll先通过epoll_ctl注册一个描述符到内核中,并一直维护着而不像poll每次操作都将所有要监控的描述符传递给内核
3.在描述符读写就绪时,通过回掉函数将自己加入就绪队列中,之后epoll_wait返回该就绪队列,所以用户不需要遍历整个文件描述符判断哪些事件就绪。性能提升。
4.支持ET高效模式。




void usage(const char* str )
 12 {
 13     printf("usage:[local_IP][local_port]\n",str);
 14 }
 15 
 16 int startup(const char* ip,int port)
 17 {
 18     int listen_sock=socket(AF_INET,SOCK_STREAM,0);
 19     if(listen<0){
 20         perror("sock");
 21         exit(2);
 22         }
 23     struct sockaddr_in  local;
 24     local.sin_family=AF_INET;
 25     local.sin_port=htons(port);
 26     local.sin_addr.s_addr=inet_addr(ip);
 27     if(bind(listen_sock,(struct sockaddr *)&local,sizeof(local))<0){
 28         perror("bind");
 29         exit(3);
 30         }
 31         if(listen(listen_sock,20)<0){
 32             perror("listen");
 33             exit(4);
 34             }
 35             return listen_sock;
 36 }
 37  int main(int argc,char* argv[])
 39 {
 40     if(argc!=3){
 41         usage(argv[0]);
 42         exit(1);
 43         }
 44         int listen_sock=startup(argv[1],atoi(argv[2]));
 45 
 46         int epollfd=epoll_create(256);
 47         if(epollfd<0){
 48             perror("epoll");
 49             close(listen_sock);
 50             exit(5);
 51             }
 52 
 53             struct epoll_event  ev;
 54             ev.events=EPOLLIN;
 55 
 56             int ret=epoll_ctl(epollfd,EPOLL_CTL_ADD,listen_sock,&ev);
 57 
 58             struct epoll_event evs[64];
 59             int timeout=1000;
 60             int nums=0;
 61 
 62             while(1){
 63                 switch(nums=epoll_wait(epollfd,evs,64,timeout)){
 64                     case 0:

64                     printf("timeout..\n");          
 65                     break;                           
 66                     case -1:                          
 67                     perror("epollwait");               
 68                     break;                              
 69                     default:{                                
 70                         int i=0;                
 71                         for(;i<64;i++){                           
 72                             int sock=evs[i].data.fd;              
 73                             if(sock==listen_sock&&(evs[i].events&EPOLLIN)){
 74                                 //listen_sock ready;
 75                                 struct sockaddr_in client;
 76                                 socklen_t len=sizeof(client);
 77                                 int new_sock=accept(listen_sock,(struct sockaddr*)&client,&len);
 78                                 if(new_sock<0){        
 79                                     perror("acceot");   
 80                                     continue;                
 81                                     }
 82                                     ev.events=EPOLLIN;
 83                                     ev.data.fd=new_sock;          
 84                                     epoll_ctl(epollfd,EPOLL_CTL_ADD,new_sock,&evs);
 85 85 
 86 
 87                                 }else if(sock!=listen_sock){
 88                                     if(evs[i].events&EPOLLIN){
 89                                         //normal ready;
 90                                         char buf[1024];
 91                                         ssize_t s=read(sock,buf,sizeof(buf)-1);
 92                                         if(s>0){
 93                                             printf("client say# :%s\n",buf);
 94                                             ev.events=EPOLLOUT;
 95                                             ev.data.fd=sock;
 96                                             epoll_ctl(epollfd,EPOLL_CTL_MOD,sock,&evs);
 97                                             }else if(s==0){
 98                                                 printf("client quit\n");
 99                                                 epoll_ctl(epollfd,EPOLL_CTL_DEL,sock,NULL);
100                                                 }else {
101                                                     perror("read");
102                                                     close(sock);
103                                             epoll_ctl(epollfd,EPOLL_CTL_MOD,sock,&ev);
104                                                     }
105                                         }
106                                     }else {
107                                         if(evs[i].events&EPOLLOUT){
108                                             //normal wrute ready
109                          const char *msg = "HTTP/1.0 200 OK\r\n\r\n<html><h1> hello epoll!</h1></html>";
110                                             write(sock,msg,strlen(msg));
111                                             }
112                                         }
                                                                                            112,6-24      83%
                                                                   

原创粉丝点击