收集未经测试的Epoll模型代码<一>

本文深入探讨了网络编程中的核心概念,包括socket接口、非阻塞I/O、多线程并发模型,以及如何利用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.    }  


IO多路复用实现个简单的web server(端口80)承载附件的web,以下是web中的index.html内容:<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html;charset=utf-8"> <title>Blog</title> <link rel="stylesheet" type="text/css" href="css/style_mobile.css"> <script language="javascript" type="text/javascript" src="js/jquery-1.9.1.min.js"></script> <script language="javascript" type="text/javascript" src="js/action.js"></script> </head> <body> <div id="container"> <div id="header"> <div id="logo">David Lanham</div> <ul> <li><a class="active" href="Index.html">Blog</a></li> <li><a href="Work.html">Work</a></li> <li><a href="About.html">About</a></li> <li><a href="Contact.html">Contact</a></li> </ul> </div> <div id="about_content"> <div id="useless"> <p class="available">This page is not Available right now!</p> <p class="page_soon">The Page of <font color="#f04922">Blog</font> will come soon!<p> </div> </div> <div id="footer"> <div id="fttext"> <p>All illustrations on this site are from the very talented</p> <p> illustrator and designer David Lanham. Make sure to</p> <p>check out his work at <a href="#">DavidLanham.com.</a></p> </div> <div id="ftimage"> <a href="#"><img src="images/footer_baby.png"></a> </div> <div id="ft_text"> <p class="ftname">David Lanham</p> <p class="ftabout">I create beatufiul illustrations and designs.<a href="#">About me.</a></p> </div> <ul> <li><a href="#"><img src="images/footer_bird.png"></a></li> <li><a href="#"><img src="images/footer_ball.png"></a></li> <li><a href="#"><img src="images/footer_be.png"></a></li> <li><a href="#"><img src="images/footer_@.png"></a></li> <li><a href="#"><img src="images/footer_message.png"></a></li> </ul> </div> </div> </body> </html>
最新发布
08-08
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值