最简单的Epoll模型代码

该模型不包含设置客户端心跳,接收,发送Timeout,多线程,还有地址复用REUSE_ADDR。最近为了能够完成书中的Linux开发部分,在重写很多模型,包含SelectClient,SelectServer,EpollClient,EpollServer模型,还有最基本的简单模型,发现Linux中的API开发要比Windows易懂的多。

另外依然有几个地方没有处理的很好,比如Event使用占满了,应该做一些处理,或者使用list或者vector来管理event,如果发现数量不够,动态来分配一些。

另外如果某个event出现问题,设置event.data.fd = -1,就可以自动达到复用的效果,这个应该用代码测试一下。从开发一个优雅的服务器来说,这段代码还远远不够,可以进行处理的地方,比如线程,线程池,内存池,用户的管理,用户数据管理,都可以采取内存池的概念,或者使用链表。


  1. /* 
  2. EPOLLOUT:表示对应的文件描述符可以写;  
  3. EPOLLPRI:表示对应的文件描述符有紧急的数据可读(我不太明白是什么意思,可能是类似client关闭 socket连接这样的事件);  
  4. EPOLLERR:表示对应的文件描述符发生错误;  
  5. EPOLLHUP:表示对应的文件描述符被挂断;  
  6. EPOLLET:表示对应的文件描述符有事件发生;  
  7. */  
  8. #include <iostream>  
  9. #include <sys/socket.h>  
  10. #include <sys/epoll.h>  
  11. #include <netinet/in.h>  
  12. #include <arpa/inet.h>  
  13. #include <fcntl.h>  
  14. #include <unistd.h>  
  15. #include <stdio.h>  
  16.   
  17. #define MAXLINE 10  
  18. #define OPEN_MAX 100  
  19. #define LISTENQ 20  
  20. #define SERV_PORT 5555  
  21. #define INFTIM 1000  
  22.   
  23. void setnonblocking(int sock)  
  24. {  
  25.      int opts;  
  26.      opts=fcntl(sock,F_GETFL);  
  27.      if(opts<0)  
  28.      {  
  29.           perror("fcntl(sock,GETFL)");  
  30.           exit(1);  
  31.      }  
  32.      opts = opts|O_NONBLOCK;  
  33.      if(fcntl(sock,F_SETFL,opts)<0)  
  34.      {  
  35.           perror("fcntl(sock,SETFL,opts)");  
  36.           exit(1);  
  37.      }      
  38. }  
  39. int main()  
  40. {  
  41.      int i, maxi, listenfd, connfd, sockfd,epfd,nfds;  
  42.      ssize_t n;  
  43.      char line[MAXLINE];  
  44.      socklen_t clilen;  
  45.      //声明epoll_event结构体的变量,ev用于注册事件,数组用于回传要处理的事件  
  46.      struct epoll_event ev,events[20];  
  47.      //生成用于处理accept的epoll专用的文件描述符  
  48.      epfd=epoll_create(256);  
  49.      struct sockaddr_in clientaddr;  
  50.      struct sockaddr_in serveraddr;  
  51.      listenfd = socket(AF_INET, SOCK_STREAM, 0);  
  52.      //把socket设置为非阻塞方式  
  53.      setnonblocking(listenfd);  
  54.      //设置与要处理的事件相关的文件描述符  
  55.      ev.data.fd=listenfd;  
  56.      //设置要处理的事件类型  
  57.      ev.events=EPOLLIN|EPOLLET;  
  58.      //注册epoll事件  
  59.      epoll_ctl(epfd,EPOLL_CTL_ADD,listenfd,&ev); //相当于Select模型的FD_SET  
  60.      bzero(&serveraddr, sizeof(serveraddr));  
  61.      serveraddr.sin_family = AF_INET;  
  62.      char *local_addr="127.0.0.1";  
  63.      inet_aton(local_addr,&(serveraddr.sin_addr));//htons(SERV_PORT);  
  64.      serveraddr.sin_port=htons(SERV_PORT);  
  65.      bind(listenfd,(sockaddr *)&serveraddr, sizeof(serveraddr));  
  66.      listen(listenfd, LISTENQ);  
  67.      maxi = 0;   
  68.      for ( ; ; ) {  
  69.           //等待epoll事件的发生  
  70.           nfds=epoll_wait(epfd,events,20,500);  
  71.           //处理所发生的所有事件        
  72.           for(i=0;i<nfds;++i)  
  73.           {  
  74.                if(events[i].data.fd==listenfd)//有客户端连入  
  75.                {  
  76.                     connfd = accept(listenfd,(sockaddr *)&clientaddr, &clilen);  
  77.                     if(connfd<0){  
  78.                          perror("connfd<0");  
  79.                          exit(1);  
  80.                     }  
  81.                     setnonblocking(connfd);  
  82.                     char *str = inet_ntoa(clientaddr.sin_addr);  
  83.                     std::cout<<"connect from "<_u115 ?tr<<std::endl;  
  84.                     //设置用于读操作的文件描述符  
  85.                     ev.data.fd=connfd;  
  86.                     //设置用于注测的读操作事件  
  87.                     ev.events=EPOLLIN|EPOLLET;  
  88.                     //注册ev  
  89.                     epoll_ctl(epfd,EPOLL_CTL_ADD,connfd,&ev);  
  90.                }  
  91.                else if(events[i].events&EPOLLIN)  
  92.                {  
  93.                     if ( (sockfd = events[i].data.fd) < 0) continue;  
  94.                     if ( (n = read(sockfd, line, MAXLINE)) < 0) {  
  95.                          if (errno == ECONNRESET) {  
  96.                               close(sockfd);  
  97.                               events[i].data.fd = -1;  
  98.                          } else   
  99.                               std::cout<<"readline error"<<std::endl;  
  100.                     } else if (n == 0) {  
  101.                          close(sockfd);  
  102.                          events[i].data.fd = -1;  
  103.                     }  
  104.                     //设置用于写操作的文件描述符  
  105.                     ev.data.fd=sockfd;  
  106.                     //设置用于注测的写操作事件  
  107.                     ev.events=EPOLLOUT|EPOLLET;  
  108.                     //修改sockfd上要处理的事件为EPOLLOUT  
  109.                     epoll_ctl(epfd,EPOLL_CTL_MOD,sockfd,&ev);  
  110.                }  
  111.                else if(events[i].events&EPOLLOUT)  
  112.                {      
  113.                     sockfd = events[i].data.fd;  
  114.                     write(sockfd, line, n);  
  115.                     //设置用于读操作的文件描述符  
  116.                     ev.data.fd=sockfd;  
  117.                     //设置用于注测的读操作事件  
  118.                     ev.events=EPOLLIN|EPOLLET;  
  119.                     //修改sockfd上要处理的事件为EPOLIN  
  120.                     epoll_ctl(epfd,EPOLL_CTL_MOD,sockfd,&ev);  
  121.                }  
  122.           }  
  123.      }  


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值