Linux Epoll

  1. #include <iostream>   
  2. #include <sys/socket.h>   
  3. #include <sys/epoll.h>   
  4. #include <netinet/in.h>   
  5. #include <arpa/inet.h>   
  6. #include <fcntl.h>   
  7. #include <unistd.h>   
  8. #include <stdio.h>   
  9. #include <pthread.h>   
  10.   
  11. #define MAXLINE 10   
  12.   
  13. #define OPEN_MAX 100   
  14.   
  15. #define LISTENQ 20   
  16.   
  17. #define SERV_PORT 5555   
  18.   
  19. #define INFTIM 1000   
  20.   
  21.   
  22. //线程池任务队列结构体   
  23.   
  24. struct  task{  
  25.   int  fd;             //需要读写的文件描述符   
  26.   
  27.   struct  task *next;  //下一个任务   
  28.   
  29. };  
  30.   
  31. //用于读写两个的两个方面传递参数   
  32.   
  33. struct  user_data{  
  34.   int  fd;  
  35.   unsigned int  n_size;  
  36.   char  line[MAXLINE];  
  37. };  
  38.   
  39. //线程的任务函数   
  40.   
  41. void  * readtask( void  *args);  
  42.   
  43. void  * writetask( void  *args);  
  44.   
  45.   
  46. //声明epoll_event结构体的变量,ev用于注册事件,数组用于回传要处理的事件   
  47.   
  48. struct  epoll_event ev,events[20];  
  49.   
  50. int  epfd;  
  51.   
  52. pthread_mutex_t mutex;  
  53.   
  54. pthread_cond_t cond1;  
  55.   
  56. struct  task *readhead=NULL,*readtail=NULL,*writehead=NULL;  
  57.   
  58.   
  59. void  setnonblocking( int  sock)  
  60. {  
  61.      int  opts;  
  62.      opts=fcntl(sock,F_GETFL);  
  63.      if (opts<0)  
  64.      {  
  65.           perror("fcntl(sock,GETFL)" );  
  66.           exit(1);  
  67.      }  
  68.     opts = opts|O_NONBLOCK;  
  69.      if (fcntl(sock,F_SETFL,opts)<0)  
  70.      {  
  71.           perror("fcntl(sock,SETFL,opts)" );  
  72.           exit(1);  
  73.      }     
  74. }  
  75.   
  76.   
  77. int  main()  
  78. {  
  79.      int  i, maxi, listenfd, connfd, sockfd,nfds;  
  80.      pthread_t tid1,tid2;  
  81.       
  82.      struct  task *new_task=NULL;  
  83.      struct  user_data *rdata=NULL;  
  84.      socklen_t clilen;  
  85.       
  86.      pthread_mutex_init(&mutex,NULL);  
  87.      pthread_cond_init(&cond1,NULL);  
  88.      //初始化用于读线程池的线程   
  89.   
  90.      pthread_create(&tid1,NULL,readtask,NULL);  
  91.      pthread_create(&tid2,NULL,readtask,NULL);  
  92.       
  93.      //生成用于处理accept的epoll专用的文件描述符      
  94.      epfd=epoll_create(256);  
  95.   
  96.      struct  sockaddr_in clientaddr;  
  97.      struct  sockaddr_in serveraddr;  
  98.      listenfd = socket(AF_INET, SOCK_STREAM, 0);  
  99.      //把socket设置为非阻塞方式   
  100.   
  101.      setnonblocking(listenfd);  
  102.      //设置与要处理的事件相关的文件描述符   
  103.   
  104.      ev.data.fd=listenfd;  
  105.      //设置要处理的事件类型   
  106.   
  107.      ev.events=EPOLLIN|EPOLLET;  
  108.      //注册epoll事件   
  109.   
  110.      epoll_ctl(epfd,EPOLL_CTL_ADD,listenfd,&ev);  
  111.       
  112.      bzero(&serveraddr, sizeof (serveraddr));  
  113.      serveraddr.sin_family = AF_INET;  
  114.       
  115.      char  *local_addr= "200.200.200.222" ;  
  116.      inet_aton(local_addr,&(serveraddr.sin_addr));//htons(SERV_PORT);   
  117.      serveraddr.sin_port=htons(SERV_PORT);  
  118.      bind(listenfd,(sockaddr *)&serveraddr, sizeof (serveraddr));  
  119.      listen(listenfd, LISTENQ);  
  120.       
  121.      maxi = 0;  
  122.      for  ( ; ; ) {  
  123.           //等待epoll事件的发生   
  124.   
  125.           nfds=epoll_wait(epfd,events,20,500);  
  126.           //处理所发生的所有事件        
  127.         for (i=0;i<nfds;++i)  
  128.         {  
  129.                if (events[i].data.fd==listenfd)  
  130.                {  
  131.                      
  132.                     connfd = accept(listenfd,(sockaddr *)&clientaddr, &clilen);  
  133.                     if (connfd<0){  
  134.                       perror("connfd<0" );  
  135.                       exit(1);  
  136.                    }  
  137.                     setnonblocking(connfd);  
  138.                      
  139.                     char  *str = inet_ntoa(clientaddr.sin_addr);  
  140.                     std::cout<<"connec_ from >>" <<str<<std::endl;  
  141.                     //设置用于读操作的文件描述符   
  142.   
  143.                     ev.data.fd=connfd;  
  144.                     //设置用于注测的读操作事件   
  145.   
  146.                  ev.events=EPOLLIN|EPOLLET;  
  147.                     //注册ev   
  148.   
  149.                  epoll_ctl(epfd,EPOLL_CTL_ADD,connfd,&ev);  
  150.                }  
  151.             else   if (events[i].events&EPOLLIN)  
  152.             {  
  153.                     printf("reading!/n" );                  
  154.                     if  ( (sockfd = events[i].data.fd) < 0)  continue ;  
  155.                     new_task=new  task();  
  156.                     new_task->fd=sockfd;  
  157.                     new_task->next=NULL;  
  158.                     //添加新的读任务   
  159.   
  160.                     pthread_mutex_lock(&mutex);  
  161.                     if (readhead==NULL)  
  162.                     {  
  163.                       readhead=new_task;  
  164.                       readtail=new_task;  
  165.                     }     
  166.                     else   
  167.   
  168.                     {     
  169.                      readtail->next=new_task;  
  170.                       readtail=new_task;  
  171.                     }     
  172.                    //唤醒所有等待cond1条件的线程   
  173.   
  174.                     pthread_cond_broadcast(&cond1);  
  175.                     pthread_mutex_unlock(&mutex);    
  176.               }  
  177.                else   if (events[i].events&EPOLLOUT)  
  178.                {     
  179.               rdata=(struct  user_data *)events[i].data.ptr;  
  180.                  sockfd = rdata->fd;  
  181.                  write(sockfd, rdata->line, rdata->n_size);  
  182.                  delete  rdata;  
  183.                  //设置用于读操作的文件描述符   
  184.   
  185.                  ev.data.fd=sockfd;  
  186.                  //设置用于注测的读操作事件   
  187.   
  188.                ev.events=EPOLLIN|EPOLLET;  
  189.                  //修改sockfd上要处理的事件为EPOLIN   
  190.   
  191.                epoll_ctl(epfd,EPOLL_CTL_MOD,sockfd,&ev);  
  192.                }  
  193.                                
  194.           }  
  195.            
  196.      }  
  197. }  
  198.   
  199. void  * readtask( void  *args)  
  200. {  
  201.      
  202.    int  fd=-1;  
  203.    unsigned int  n;  
  204.    //用于把读出来的数据传递出去   
  205.   
  206.    struct  user_data *data = NULL;  
  207.    while (1){  
  208.           
  209.         pthread_mutex_lock(&mutex);  
  210.         //等待到任务队列不为空   
  211.   
  212.         while (readhead==NULL)  
  213.              pthread_cond_wait(&cond1,&mutex);  
  214.           
  215.         fd=readhead->fd;  
  216.         //从任务队列取出一个读任务   
  217.   
  218.         struct  task *tmp=readhead;  
  219.         readhead = readhead->next;  
  220.         delete  tmp;  
  221.         pthread_mutex_unlock(&mutex);  
  222.         data = new  user_data();  
  223.         data->fd=fd;  
  224.         if  ( (n = read(fd, data->line, MAXLINE)) < 0) {  
  225.              
  226.            if  (errno == ECONNRESET) {  
  227.              close(fd);  
  228.                
  229.           } else   
  230.   
  231.              std::cout<<"readline error" <<std::endl;  
  232.            if (data!=NULL) delete  data;  
  233.         } else   if  (n == 0) {  
  234.             close(fd);  
  235.            printf("Client close connect!/n" );  
  236.            if (data!=NULL) delete  data;  
  237.         } else {  
  238.           
  239.         data->n_size=n;  
  240.         //设置需要传递出去的数据   
  241.   
  242.         ev.data.ptr=data;  
  243.         //设置用于注测的写操作事件   
  244.   
  245.         ev.events=EPOLLOUT|EPOLLET;  
  246.         //修改sockfd上要处理的事件为EPOLLOUT   
  247.   
  248.         epoll_ctl(epfd,EPOLL_CTL_MOD,fd,&ev);  
  249.        }  
  250.    }  

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值