收集未经测试的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
    评论
select模型epoll模型都属于多路转接模型,用于处理大量客户端并发需求中的socket模型问题。 select模型的操作流程是通过调用select函数,将需要进行I/O操作的文件描述符集合传递给内核,内核会监视这些文件描述符是否有可读或可写事件发生,然后返回就绪的文件描述符集合给应用程序进行处理。select模型代码操作包括设置文件描述符集合、调用select函数以及处理返回的就绪文件描述符集合。select模型的优缺点分析:优点是跨平台支持良好,适用于小规模的并发连接;缺点是效率低下,当并发连接数量增多时,每次都需要遍历整个文件描述符集合。 epoll模型的操作流程是通过调用epoll_ctl函数注册要监视的文件描述符以及关注的事件类型,然后通过调用epoll_wait函数等待事件的发生,一旦有就绪事件发生,内核会将就绪的事件信息返回给应用程序进行处理。epoll模型代码操作包括注册文件描述符和事件、调用epoll_wait函数等待事件的发生以及处理返回的就绪事件。epoll模型的监控流程是由内核负责监视文件描述符的状态变化,并在有就绪事件时通知应用程序。epoll模型具有高效的事件通知机制,能够支持大规模的并发连接。它使用了事件驱动的方式,只需要关注就绪的事件,避免了无效的遍历,因此效率更高。 select模型epoll模型的主要区别在于效率和可扩展性方面。select模型适用于小规模的并发连接,而epoll模型适用于大规模的并发连接。epoll模型通过使用内核事件通知机制,只关注就绪的事件,避免了无效的遍历,因此在处理大量并发连接时具有更高的效率。但是,epoll模型的使用需要更多的代码和复杂的管理逻辑。 总结起来,select模型适用于小规模的并发连接,而epoll模型适用于大规模的并发连接,并且具有更高的效率和可扩展性。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [【Linux】多路转接之select、poll、epoll模型](https://blog.csdn.net/weixin_43939593/article/details/106651301)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* *3* [socket网络通信模型之select与epoll](https://blog.csdn.net/chenlycly/article/details/123717804)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值