热门关键字:  ubuntu  分区  Fedora  linux系统进程  函数

当前位置 :| 主页>Linux教程>内核研究>

linux2.6内核epoll用法举例说明

来源: 作者: 时间:2007-12-03 Tag: 点击:
       linux2.6内核epoll用法举例说明
epoll用到的所有函数都是在头文件sys/epoll.h中声明的,下面简要说明所用到的数据结构和函数:
  所用到的数据结构
  typedef union epoll_data {
  void *ptr;
  int fd;
  __uint32_t u32;
  __uint64_t u64;
  } epoll_data_t;
  struct epoll_event {
  __uint32_t events; /* Epoll events */
  epoll_data_t data; /* User data variable */
  };
  结构体epoll_event 被用于注册所感兴趣的事件和回传所发生待处理的事件,其中epoll_data 联合体用来保存触发事件的某个文件描述符相关的数据,例如一个client连接到服务器,服务器通过调用accept函数可以得到于这个client对应的socket文件描述符,可以把这文件描述符赋给epoll_data的fd字段以便后面的读写操作在这个文件描述符上进行。epoll_event 结构体的events字段是表示感兴趣的事件和被触发的事件可能的取值为:EPOLLIN :表示对应的文件描述符可以读;
  EPOLLOUT:表示对应的文件描述符可以写;
  EPOLLPRI:表示对应的文件描述符有紧急的数据可读(我不太明白是什么意思,可能是类似client关闭 socket连接这样的事件);
  EPOLLERR:表示对应的文件描述符发生错误;
  EPOLLHUP:表示对应的文件描述符被挂断;
  EPOLLET:表示对应的文件描述符有事件发生;
  所用到的函数:
  1、epoll_create函数
  函数声明:int epoll_create(int size)
  该函数生成一个epoll专用的文件描述符,其中的参数是指定生成描述符的最大范围(我觉得这个参数和select函数的第一个参数应该是类似的但是该怎么设置才好,我也不太清楚)。
  2、epoll_ctl函数
  函数声明:int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event)
  该函数用于控制某个文件描述符上的事件,可以注册事件,修改事件,删除事件。
  参数:epfd:由 epoll_create 生成的epoll专用的文件描述符;
  op:要进行的操作例如注册事件,可能的取值EPOLL_CTL_ADD 注册、EPOLL_CTL_MOD 修
  改、EPOLL_CTL_DEL 删除
  fd:关联的文件描述符;
  event:指向epoll_event的指针;
  如果调用成功返回0,不成功返回-1
  3、epoll_wait函数
  函数声明:int epoll_wait(int epfd,struct epoll_event * events,int maxevents,int timeout)
  该函数用于轮询I/O事件的发生;
  参数:
  epfd:由epoll_create 生成的epoll专用的文件描述符;
  epoll_event:用于回传代处理事件的数组;
  maxevents:每次能处理的事件数;
  timeout:等待I/O事件发生的超时值;
  返回发生事件数。
  例子:
  代码:
  #include <iostream>
  #include <sys/socket.h>
  #include <sys/epoll.h>
  #include <netinet/in.h>
  #include <arpa/inet.h>
  #include <fcntl.h>
  #include <unistd.h>
  #include <stdio.h>
  #define MAXLINE 10
  #define OPEN_MAX 100
  #define LISTENQ 20
  #define SERV_PORT 5555
  #define INFTIM 1000
  void setnonblocking(int sock)
  {
  int opts;
  opts=fcntl(sock,F_GETFL);
  if(opts<0)
  {
  perror("fcntl(sock,GETFL)");
  exit(1);
  }
  opts = opts|O_NONBLOCK;
  if(fcntl(sock,F_SETFL,opts)<0)
  {
  perror("fcntl(sock,SETFL,opts)");
  exit(1);
  }
  }
  int main()
  {
  int i, maxi, listenfd, connfd, sockfd,epfd,nfds;
  ssize_t n;
  char line[MAXLINE];
  socklen_t clilen;
  //声明epoll_event结构体的变量,ev用于注册事件,数组用于回传要处理的事件
  struct epoll_event ev,events[20];
  //生成用于处理accept的epoll专用的文件描述符
  epfd=epoll_create(256);
  struct sockaddr_in clientaddr;
  struct sockaddr_in serveraddr;
  listenfd = socket(AF_INET, SOCK_STREAM, 0);
  //把socket设置为非阻塞方式
  setnonblocking(listenfd);
  //设置与要处理的事件相关的文件描述符
  ev.data.fd=listenfd;
  //设置要处理的事件类型
  ev.events=EPOLLIN|EPOLLET;
  //注册epoll事件
  epoll_ctl(epfd,EPOLL_CTL_ADD,listenfd,&ev);
  bzero(&serveraddr, sizeof(serveraddr));
  serveraddr.sin_family = AF_INET;
  char *local_addr="200.200.200.204";
  inet_aton(local_addr,&(serveraddr.sin_addr));//htons(SERV_PORT);
  serveraddr.sin_port=htons(SERV_PORT);
  bind(listenfd,(sockaddr *)&serveraddr, sizeof(serveraddr));
  listen(listenfd, LISTENQ);
  maxi = 0;
  for ( ; ; ) {
  //等待epoll事件的发生
  nfds=epoll_wait(epfd,events,20,500);
  //处理所发生的所有事件
  for(i=0;i<nfds;++i)
  {
  if(events[i].data.fd==listenfd)
  {
  connfd = accept(listenfd,(sockaddr *)&clientaddr, &clilen);
  if(connfd<0){
  perror("connfd<0");
  exit(1);
  }
  setnonblocking(connfd);
  char *str = inet_ntoa(clientaddr.sin_addr);
  std::cout<<"connect from "<_u115 ?tr<<std::endl;
  //设置用于读操作的文件描述符
  ev.data.fd=connfd;
  //设置用于注测的读操作事件
  ev.events=EPOLLIN|EPOLLET;
  //注册ev
  epoll_ctl(epfd,EPOLL_CTL_ADD,connfd,&ev);
  }
  else if(events[i].events&EPOLLIN)
  {
  if ( (sockfd = events[i].data.fd) < 0) continue;
  if ( (n = read(sockfd, line, MAXLINE)) < 0) {
  if (errno == ECONNRESET) {
  close(sockfd);
  events[i].data.fd = -1;
  } else
  std::cout<<"readline error"<<std::endl;
  } else if (n == 0) {
  close(sockfd);
  events[i].data.fd = -1;
  }
  //设置用于写操作的文件描述符
  ev.data.fd=sockfd;
  //设置用于注测的写操作事件
  ev.events=EPOLLOUT|EPOLLET;
  //修改sockfd上要处理的事件为EPOLLOUT
  epoll_ctl(epfd,EPOLL_CTL_MOD,sockfd,&ev);
  }
  else if(events[i].events&EPOLLOUT)
  {
  sockfd = events[i].data.fd;
  write(sockfd, line, n);
  //设置用于读操作的文件描述符
  ev.data.fd=sockfd;
  //设置用于注测的读操作事件
  ev.events=EPOLLIN|EPOLLET;
  //修改sockfd上要处理的事件为EPOLIN
  epoll_ctl(epfd,EPOLL_CTL_MOD,sockfd,&ev);
  }
  }
  }
  }



相关文章:
精通initramfs构建step by step
Linux利用kexec迅速切换内核
进程上下文VS中断上下文
内核通知链 学习笔记
linux spi子系统驱动分析
menuconfig 配置选项
《Linux操作系统内核实习》之练习一
udev详解
什么叫微内核,宏内核?
Linux 信号signal处理机制
开发简单的 Linux2.6 内核模块
删除内核的perl脚本
Linux2.6内核usb gadget驱动移植
GCC hacks in the Linux kernel
iomem
kernel学习的想法
让自己的驱动支持udev
linux内核编译步骤
内核的等待队列
Linux内核wait_queue深入分析
升级和删除内核
SD卡驱动分析2
Linux Kernel VDSO本地权限提升漏洞
内核中的TCP的追踪分析-15-TCP(IPV4)的客户端与
linux 2.6内核可加载模块的编译
内核模块HelloWorld
在环回接口上发送一个数据报
ARP初始化
1分钟编译FreeBSD内核
linux设备模型之uart驱动架构分析