Linux I/O多路复用详解及实例

2019-10-13 18:20:34王旭

模型

epoll_create()     //创建epoll对象
struct epoll_event   //准备事件结构体和事件结构体数组
  event.events
  event.data.fd ...
epoll_ctl()       //配置epoll对象
epoll_wait()      //监控epoll对象中的fd及其相应的event

例子_I/O多路复用并发服务器

/* ... */

int main()
{
  /* ... */
  /* 创建epoll对象 */
  int epoll_fd = epoll_create(1024);
  
  //准备一个事件结构体
  struct epoll_event event = {0};
  event.events = EPOLLIN;
  event.data.fd = listenfd;  //data是一个共用体,除了fd还可以返回其他数据
  
  //ctl是监控listenfd是否有event被触发
  //如果发生了就把event通过wait带出。
  //所以,如果event里不标明fd,我们将来获取就不知道哪个fd
  epoll_ctl(epoll_fd, EPOLL_CTL_ADD, listenfd, &event);
  
  struct epoll_event revents[MAXNFD] = {0};
  int nready;
  char buf[MAXNFD][BUFSIZE] = {0};
  while(1){
    //wait返回等待的event发生的数目
    //并把相应的event放到event类型的数组中
    nready = epoll_wait(epoll_fd, revents, MAXNFD, -1)
    int i = 0;
    for(;i<nready; i++){
      //wait通过在events中设置相应的位来表示相应事件的发生
      //如果输入可用,那么下面的这个结果应该为真
      if(revents[i].events & EPOLLIN){
        //如果是listenfd有数据输入
        if(revents[i].data.fd == listenfd){
          int sockfd = accept(listenfd, (struct sockaddr*)&clientaddr, &len);
          struct epoll_event event = {0};
          event.events = EPOLLIN;
          event.data.fd = sockfd;
          epoll_ctl(epoll_fd, EPOLL_CTL_ADD, sockfd, &event);
        }
        else{
          int ret = read(revents[i].data.fd, buf[revents[i].data.fd], sizeof buf[0]);
          if(0 == ret){
            close(revents[i].data.fd);
            epoll_ctl(epoll_fd, EPOLL_CTL_DEL, revents[i].data.fd, &revents[i]);
          }
          
          revents[i].events = EPOLLOUT;
          epoll_ctl(epoll_fd, EPOLL_CTL_MOD, revents[i].data.fd, &revents[i]);
        }
      }
      else if(revents[i].events & EPOLLOUT){
        int ret = write(revents[i].data.fd, buf[revents[i].data.fd], sizeof buf[0]);
        revents[i].events = EPOLLIN;
        epoll_ctl(epoll_fd, EPOLL_CTL_MOD, revents[i].data.fd, &revents[i]);
      }
    }
  }
  close(listenfd);
}



感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!