linux 2.6内核epoll用法举例

 
  1. linux 2.6内核epoll用法举例说明(续)--给echo服务器增加读线程池
  2. 上篇文章使用linux内核2.6 提供的epoll机制实现了一个反应式echo服务器,使用反应式服务器的最大好处就是可以按cpu的数量来配置线程池内线程的线程数而不是根据客户端的并发量配置线程池。我是第一次使用pthread库来写线程池,使用的是工作队列方式的线程池。我感觉作队列方式的线程池可以当成一种设计模式来用的,在很多平台上都是可以按这种方式来实现线程池,从win32 ,unix到jvm都是适用的
  3.  
  4. #include
  5. #include
  6. #include
  7. #include
  8. #include
  9. #include
  10. #include
  11. #include
  12. #include
  13.  
  14. #define MAXLINE 10
  15. #define OPEN_MAX 100
  16. #define LISTENQ 20
  17. #define SERV_PORT 5555
  18. #define INFTIM 1000
  19.  
  20. //线程池任务队列结构体
  21. struct task{
  22.   int fd;            //需要读写的文件描述符
  23.   struct task *next; //下一个任务
  24. };
  25.  
  26. //用于读写两个的两个方面传递参数
  27. struct user_data{
  28.   int fd;
  29.   unsigned int n_size;
  30.   char line[MAXLINE];
  31. };
  32.  
  33. //线程的任务函数
  34. void * readtask(void *args);
  35. void * writetask(void *args);
  36.  
  37.  
  38. //声明epoll_event结构体的变量,ev用于注册事件,数组用于回传要处理的事件
  39. struct epoll_event ev,events[20];
  40. int epfd;
  41. pthread_mutex_t mutex;
  42. pthread_cond_t cond1;
  43. struct task *readhead=NULL,*readtail=NULL,*writehead=NULL;
  44.  
  45. void setnonblocking(int sock)
  46. {
  47.      int opts;
  48.      opts=fcntl(sock,F_GETFL);
  49.      if(opts<0)
  50.      {
  51.           perror("fcntl(sock,GETFL)");
  52.           exit(1);
  53.      }
  54.     opts = opts|O_NONBLOCK;
  55.      if(fcntl(sock,F_SETFL,opts)<0)
  56.      {
  57.           perror("fcntl(sock,SETFL,opts)");
  58.           exit(1);
  59.      }   
  60. }
  61.  
  62. int main()
  63. {
  64.      int i, maxi, listenfd, connfd, sockfd,nfds;
  65.      pthread_t tid1,tid2;
  66.     
  67.      struct task *new_task=NULL;
  68.      struct user_data *rdata=NULL;
  69.      socklen_t clilen;
  70.     
  71.      pthread_mutex_init(&mutex,NULL);
  72.      pthread_cond_init(&cond1,NULL);
  73.      //初始化用于读线程池的线程
  74.      pthread_create(&tid1,NULL,readtask,NULL);
  75.      pthread_create(&tid2,NULL,readtask,NULL);
  76.     
  77.      //生成用于处理accept的epoll专用的文件描述符   
  78.      epfd=epoll_create(256);
  79.  
  80.      struct sockaddr_in clientaddr;
  81.      struct sockaddr_in serveraddr;
  82.      listenfd = socket(AF_INET, SOCK_STREAM, 0);
  83.      //把socket设置为非阻塞方式
  84.      setnonblocking(listenfd);
  85.      //设置与要处理的事件相关的文件描述符
  86.      ev.data.fd=listenfd;
  87.      //设置要处理的事件类型
  88.      ev.events=EPOLLIN|EPOLLET;
  89.      //注册epoll事件
  90.      epoll_ctl(epfd,EPOLL_CTL_ADD,listenfd,&ev);
  91.     
  92.      bzero(&serveraddr, sizeof(serveraddr));
  93.      serveraddr.sin_family = AF_INET;
  94.     
  95.      char *local_addr="200.200.200.222";
  96.      inet_aton(local_addr,&(serveraddr.sin_addr));//htons(SERV_PORT);
  97.      serveraddr.sin_port=htons(SERV_PORT);
  98.      bind(listenfd,(sockaddr *)&serveraddr, sizeof(serveraddr));
  99.      listen(listenfd, LISTENQ);
  100.     
  101.      maxi = 0;
  102.      for ( ; ; ) {
  103.           //等待epoll事件的发生
  104.           nfds=epoll_wait(epfd,events,20,500);
  105.           //处理所发生的所有事件     
  106.         for(i=0;i
  107.         {
  108.                if(events[i].data.fd==listenfd)
  109.                {
  110.                    
  111.                     connfd = accept(listenfd,(sockaddr *)&clientaddr, &clilen);
  112.                     if(connfd<0){
  113.                       perror("connfd<0");
  114.                       exit(1);
  115.                    }
  116.                     setnonblocking(connfd);
  117.                    
  118.                     char *str = inet_ntoa(clientaddr.sin_addr);
  119.                     std::cout<<"connec_ from >>"<
  120.                     //设置用于读操作的文件描述符
  121.                     ev.data.fd=connfd;
  122.                     //设置用于注测的读操作事件
  123.                  ev.events=EPOLLIN|EPOLLET;
  124.                     //注册ev
  125.                  epoll_ctl(epfd,EPOLL_CTL_ADD,connfd,&ev);
  126.                }
  127.             else if(events[i].events&EPOLLIN)
  128.             {
  129.                     printf("reading!/n");                
  130.                     if ( (sockfd = events[i].data.fd) < 0) continue;
  131.                     new_task=new task();
  132.                     new_task->fd=sockfd;
  133.                     new_task->next=NULL;
  134.                     //添加新的读任务
  135.                     pthread_mutex_lock(&mutex);
  136.                     if(readhead==NULL)
  137.                     {
  138.                       readhead=new_task;
  139.                       readtail=new_task;
  140.                     }   
  141.                     else
  142.                     {   
  143.                      readtail->next=new_task;
  144.                       readtail=new_task;
  145.                     }   
  146.                    //唤醒所有等待cond1条件的线程
  147.                     pthread_cond_broadcast(&cond1);
  148.                     pthread_mutex_unlock(&mutex);  
  149.               }
  150.                else if(events[i].events&EPOLLOUT)
  151.                {   
  152.               rdata=(struct user_data *)events[i].data.ptr;
  153.                  sockfd = rdata->fd;
  154.                  write(sockfd, rdata->line, rdata->n_size);
  155.                  delete rdata;
  156.                  //设置用于读操作的文件描述符
  157.                  ev.data.fd=sockfd;
  158.                  //设置用于注测的读操作事件
  159.                ev.events=EPOLLIN|EPOLLET;
  160.                  //修改sockfd上要处理的事件为EPOLIN
  161.                epoll_ctl(epfd,EPOLL_CTL_MOD,sockfd,&ev);
  162.                }
  163.                              
  164.           }
  165.          
  166.      }
  167. }
  168. void * readtask(void *args)
  169. {
  170.    
  171.    int fd=-1;
  172.    unsigned int n;
  173.    //用于把读出来的数据传递出去
  174.    struct user_data *data = NULL;
  175.    while(1){
  176.         
  177.         pthread_mutex_lock(&mutex);
  178.         //等待到任务队列不为空
  179.         while(readhead==NULL)
  180.              pthread_cond_wait(&cond1,&mutex);
  181.         
  182.         fd=readhead->fd;
  183.         //从任务队列取出一个读任务
  184.         struct task *tmp=readhead;
  185.         readhead = readhead->next;
  186.         delete tmp;
  187.         pthread_mutex_unlock(&mutex);
  188.         data = new user_data();
  189.         data->fd=fd;
  190.         if ( (n = read(fd, data->line, MAXLINE)) < 0) {
  191.            
  192.            if (errno == ECONNRESET) {
  193.              close(fd);
  194.              
  195.           } else
  196.              std::cout<<"readline error"<
  197.            if(data!=NULL)delete data;
  198.         } else if (n == 0) {
  199.             close(fd);
  200.            printf("Client close connect!/n");
  201.            if(data!=NULL)delete data;
  202.         } else{
  203.         
  204.         data->n_size=n;
  205.         //设置需要传递出去的数据
  206.         ev.data.ptr=data;
  207.         //设置用于注测的写操作事件
  208.         ev.events=EPOLLOUT|EPOLLET;
  209.         //修改sockfd上要处理的事件为EPOLLOUT
  210.         epoll_ctl(epfd,EPOLL_CTL_MOD,fd,&ev);
  211.        }
  212.    }
  213. }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值