Chinaunix首页 | 论坛 | 博客
  • 博客访问: 268820
  • 博文数量: 84
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 927
  • 用 户 组: 普通用户
  • 注册时间: 2015-03-06 23:00
个人简介

growing

文章分类

全部博文(84)

文章存档

2017年(6)

2016年(61)

2015年(17)

我的朋友

分类: 网络与安全

2016-08-11 20:07:44

一、select、poll、epoll区别

从上一个博客的代码可以看到:
select提供一个fd_set类型的集合来存储监听事件

poll则是用struct pollfd来存储监听事件,struct pollfd中有:所管理事件的文件描述符fd、所关心的事件类型events(比如POLLIN),输出行参数revents(通知用户事件的就绪状态);
可以看到上面两个都是需要遍历事件集合来判断事件是否就绪,而且事件集合的个数也有一定限制,epoll的高效主要体现再epoll_wait,原因在于epoll_wait的返回值:当返回值大于0时,是告诉当前用户的就绪事件个数,并且把这写事件按照顺序从头排列到用户提供的events里(红黑树存储),
这样就不用遍历了,
而且epoll有两种出发方式:LT水平触发(有就绪事件就一直通知,最好将当前IO设置为非阻塞的),ET边沿触发(只有新的事件到来时才会通知,高效)

二、应用实例


1.epoll

  1. #include<stdio.h>
  2. #include<unistd.h>
  3. #include<sys/types.h>
  4. #include<sys/socket.h>
  5. #include<netinet/in.h>
  6. #include<arpa/inet.h>
  7. #include<sys/epoll.h>
  8. #include<fcntl.h>
  9. #include<stdlib.h>
  10. #include<string.h>

  11. int creat_socket(char *ip,char* port)
  12. {
  13.     int sock = socket(AF_INET,SOCK_STREAM,0);
  14.     if(sock < 0){
  15.         perror("socket");
  16.         exit(2);
  17.     }

  18.     //调用setsockopt使当server先断开时避免进入TIME_WAIT状态,\
  19.      将其属性设定为SO_REUSEADDR,使其地址信息可被重用
  20.     int opt = 1;
  21.     if(setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt)) < 0){
  22.         perror("setsockopt");
  23.         exit(3);
  24.     }

  25.     struct sockaddr_in local;

  26.     local.sin_family = AF_INET;
  27.     local.sin_port = htons(atoi(port));
  28.     local.sin_addr.s_addr = inet_addr(ip);

  29.     if( bind(sock,(struct sockaddr*)&local,sizeof(local)) < 0 ){
  30.         perror("bind");
  31.         exit(4);
  32.     }

  33.     if(listen(sock,5) < 0){
  34.         perror("listen");
  35.         exit(5);
  36.     }
  37.     
  38.     printf("listen and bind succeed\n");

  39.     return sock;
  40. }

  41. int set_noblock(int sock)
  42. {
  43.     int fl = fcntl(sock,F_GETFL);
  44.     return fcntl(sock,F_SETFL,fl|O_NONBLOCK);
  45. }

  46. int main(int argc,char *argv[])
  47. {
  48.     if(argc != 3){
  49.         printf("please use:%s [ip] [port]",argv[0]);
  50.         exit(1);
  51.     }
  52.     int listen_sock = creat_socket(argv[1],argv[2]);

  53.     int epoll_fd = epoll_create(256);
  54.     if(epoll_fd < 0){
  55.         perror("epoll creat");
  56.         exit(6);
  57.     }

  58.     struct epoll_event ep_ev;
  59.     ep_ev.events = EPOLLIN;//数据的读取
  60.     ep_ev.data.fd = listen_sock;

  61.     //添加关心的事件
  62.     if(epoll_ctl(epoll_fd,EPOLL_CTL_ADD,listen_sock,&ep_ev) < 0){
  63.         perror("epoll_ctl");
  64.         exit(7);
  65.     }

  66.     struct epoll_event ready_ev[128];//申请空间来放就绪的事件。
  67.     int maxnum = 128;
  68.     int timeout = 1000;//设置超时时间,若为-1,则永久阻塞等待。
  69.     int ret = 0;
  70.     
  71.     int done = 0;
  72.     while(!done){
  73.         switch(ret = epoll_wait(epoll_fd,ready_ev,maxnum,timeout)){
  74.             case -1:
  75.                 perror("epoll_wait");
  76.                 break;
  77.             case 0:
  78.                 printf("time out...\n");
  79.                 break;
  80.             default://至少有一个事件就绪
  81.             {
  82.                 int i = 0;
  83.                 for(;i < ret;++i){
  84.                     //判断是否为监听套接字,是的话accept
  85.                     int fd = ready_ev[i].data.fd;
  86.                     if((fd == listen_sock) && (ready_ev[i].events & EPOLLIN)){
  87.                         struct sockaddr_in remote;
  88.                         socklen_t len = sizeof(remote);

  89.                         int accept_sock = accept(listen_sock,(struct sockaddr*)&remote,&len);
  90.                         if(accept_sock < 0){
  91.                             perror("accept");
  92.                             continue;
  93.                         }
  94.                         printf("accept a client..[ip]: %s,[port]: %d\n",inet_ntoa(remote.sin_addr),ntohs(remote.sin_port));
  95.                         //将新的事件添加到epoll集合中
  96.                         ep_ev.events = EPOLLIN | EPOLLET;
  97.                         ep_ev.data.fd = accept_sock;

  98.                         set_noblock(accept_sock);

  99.                         if(epoll_ctl(epoll_fd,EPOLL_CTL_ADD,accept_sock,&ep_ev) < 0){
  100.                             perror("epoll_ctl");
  101.                             close(accept_sock);
  102.                         }
  103.                     }
  104.                     else{//普通IO
  105.                          if(ready_ev[i].events & EPOLLIN){
  106.                              //申请空间同时存文件描述符和缓冲区地址

  107.                              char buf[102400];
  108.                              memset(buf,'\0',sizeof(buf));

  109.                              ssize_t _s = recv(fd,buf,sizeof(buf)-1,0);
  110.                              if(_s < 0){
  111.                                  perror("recv");
  112.                                  continue;
  113.                              }else if(_s == 0){
  114.                                  printf("remote close..\n");
  115.                                 //远端关闭了,进行善后
  116.                                  epoll_ctl(epoll_fd,EPOLL_CTL_DEL,fd,NULL);
  117.                                  close(fd);
  118.                              }else{
  119.                                  //读取成功,输出数据
  120.                                  printf("client# %s",buf);
  121.                                  fflush(stdout);

  122.                                  //将事件改写为关心事件,进行回写
  123.                                  ep_ev.data.fd = fd;
  124.                                  ep_ev.events = EPOLLOUT | EPOLLET;

  125.                                  //在epoll实例中更改同一个事件
  126.                                  epoll_ctl(epoll_fd,EPOLL_CTL_MOD,fd,&ep_ev);
  127.                              }
  128.                          }else if(ready_ev[i].events & EPOLLOUT){
  129.                                  const char*msg = "HTTP/1.1 200 OK \r\n\r\n

    hi girl

    \r\n"
    ;
  130.                                  send(fd,msg,strlen(msg),0);
  131.                                  epoll_ctl(epoll_fd,EPOLL_CTL_DEL,fd,NULL);
  132.                                  close(fd);
  133.                             }
  134.                         }
  135.                     }
  136.                 }
  137.                 break;
  138.             
  139.         }
  140.     }
  141.     close(listen_sock);
  142.     return 0;
  143. }


2.poll(跟epoll区别了一下,就不写刚开始的socket了)

  1. #include <stdio.h>
  2. #include <poll.h>
  3. #include <string.h>

  4. int main()
  5. {
  6.     int timeout = 3000;            
  7.     char buf[1024];
  8.     struct pollfd fd_poll[1];     //设置只有一个事件

  9.     while(1){
  10.         fd_poll[0].fd = 0;
  11.         fd_poll[0].events = POLLIN;
  12.         fd_poll[0].revents = 0;    

  13.         memset(buf, '\0', sizeof(buf));
  14.         switch( poll(fd_poll, 1, timeout) ){
  15.             case 0:
  16.                 perror("timeout!");
  17.                 break;
  18.             case -1:
  19.                 perror("poll");
  20.                 break;
  21.             default:
  22.                 {
  23.                     if( fd_poll[0].revents & POLLIN ){

  24.                         gets(buf);
  25.                         printf("buf : %s\n",buf);
  26.                     }
  27.                 }
  28.                 break;
  29.         }
  30.     }
  31.     return 0;
  32. }
阅读(1774) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~