Chinaunix首页 | 论坛 | 博客
  • 博客访问: 4567043
  • 博文数量: 385
  • 博客积分: 21208
  • 博客等级: 上将
  • 技术积分: 4393
  • 用 户 组: 普通用户
  • 注册时间: 2006-09-30 13:40
文章分类

全部博文(385)

文章存档

2015年(1)

2014年(3)

2012年(16)

2011年(42)

2010年(1)

2009年(2)

2008年(34)

2007年(188)

2006年(110)

分类: LINUX

2008-08-23 18:05:09



#include
int select(int numfds, fd_set * readfds, fd_set * writefds, fd_set * exceptfds, struct timeval * timeout);
numfds:文件描述符的数量从0开始,取最大的文件描述符大
readfds:当数据可以读出时返回
writefds:当writefds中任何一个准备好写入时返回
exceptfds:监控发生例外的文件描述符
timeout:NULL时将一直等待

FD_ZERO(fd_set * fds);  //清除fd_set里的任何文件描述符
FD_SET(int fd, fd_set * fds);  //把fd加入到fds的文件描述符的集合中
FD_CLR(int fd, fd_set * fds);  //把fd从fds的文件描述符的集合中删除掉
FD_ISSET(int fd, fd_set * fds);  //测试文件描述符fd是否在fds集合中 如果真返回1 假返回0
//fd_set 是一组文件描述符

#include
struct timeval
{
 int tv_sec;  //秒
 int tv_usec;  //毫秒
}

例:
[root@kaven ctest]# cat select.c
#include
#include
#include
#include

int main(void)
{
 int fds[2];
 char buf[4096];
 int i,rc,maxfd;
 fd_set watchset;
 fd_set inset;

 if((fds[0]=open("p1",O_RDONLY | O_NONBLOCK))<0)
  {
    perror("open p1");
    return 1;
  }
  if((fds[1]=open("p2",O_RDONLY | O_NONBLOCK))<0)
  {
    perror("open p2");
    return 1;
  }

 FD_ZERO(&watchset);
 FD_SET(fds[0],&watchset);
 FD_SET(fds[1],&watchset);

 maxfd=fds[0]>fds[1]?fds[0]:fds[1];
 while(FD_ISSET(fds[0],&watchset)||FD_ISSET(fds[1],&watchset))
 {
  inset=watchset;
  if(select(maxfd+1,&inset,NULL,NULL,NULL)<0)
  {
   perror("select");
   return 1;
  }
  for(i=0; i<2; i++)
  {
   if(FD_ISSET(fds[i],&inset))
   {
    rc=read(fds[i],buf,sizeof(buf)-1);
    if(rc<0)
    {
     perror("read");
     return 1;
    }
    else if(!rc)
    {
     close(fds[i]);
     FD_CLR(fds[i],&watchset);
    }
    else
    {
     buf[rc]='\0';
     printf("read: %s",buf);
    }
   }
  }
 }
 return 0;
}

比较poll()和select()
两者最重要的区别是性能方面的区别
(1)当用select时,内核必须检查从0到numfds-1的所有文件描述符,以发现应用程序是否对文件描述符对应的IO感兴趣,对于打开大量文件将产生浪费
(2)对于selelt而言,文件描述符的集合是一个位图,每一位代表一个意义;而poll是一个列表传送给内核的,相对于select效率低
(3)因为内核更新传送到select的数据结构在每次调用select的时候应用程序都必须重置这些数据结构,如果使用poll,内核传递只限于revents,避免了每次调用前的重置操作。
(4)在进程增加文件描述符数量时,由于fd_set是静态的,最多为1023个,如果大于1023的话则不能使用select

性能比较
#include
#include
#include
#include
#include
#include

#define HIGH_FD 1000

int gotAlarm;
void catch(int sig)
{
 gotAlarm=1;
}
int main(int argc, const char **argv)
{
 int devZero, count;
 fd_set selectFds;
 struct pollfd pollFds;
 devZero=open("dev/zero", O_RDONLY);
///dev/zero 是linux下的一个特殊的设备,表示全部为0的字符块。使用它作输入可以得到全为空的文件,因此可用来创建新文件或以覆盖的方式清除旧文件。
 dup2(devZero, HIGH_FD);
 signal(SIGALRM, catch);

 gotAlarm=0;
 count=0;
 alarm(1);
 while(!gotAlarm)
 {
  FD_ZERO(&selectFds);
  FD_SET(HIGH_FD,&selectFds);
  select(HIGH_FD+1,&selectFds, NULL, NULL, NULL);
  count++;
 }
 printf("select() calls per second: %d\n", count);

 pollFds.fd=HIGH_FD;
 pollFds.events=POLLIN;
 count=0;
 gotAlarm=0;
 alarm(1);
 while(!gotAlarm)
 {
  poll(&pollFds,0,0);
  count++;
 }
 printf("poll() call per second: %d",count);
 return 0;
}

epoll是在内核2.6引入的方法
#include
int epoll_create(int numDescriptors); //创建epoll文件描述符
                                                          //numDescriptors创建多少个文件描述符

int epoll_ctl(int epfd, int op, int fd, struct epoll_event * event)
op:EPOLL_CTL_ADD 把event添加到文件描述符集epfd中
        EPOLL_CTL_DEL 把event从文件描述符集epfd中删除掉
        EPOLL_CTL_MOD 对epfd中的event中的信息更新

int epoll_wait(int epfd, struct epoll_event * event, int maxevents, int timeout)
//堵塞直到有一个或多个数据可读或可写
//event和maxevents指定了缓冲区的结构 返回缓冲区里分配了多少个event结构
//当超时函数返回0,

struct epoll_event
{
 int events;  //指定哪种事件将被监控
 union
 {
  void * ptr;
  int fd;
  unsigned int u32;
  unsigned long u64;
 }data;  //只要有相应的事件发生,date就返回相应的程序,知道哪个文件描述符需要处理
};

events的取值:
EPOLLIN
EPOLLOUT
EPOLLPRI
EPOLLERR
EPOLLHUP

#include
#include
#include
#include
#include
#include

void addevent(int epfd, char * filename)
{
 int fd;
 struct epoll_event event;
 if((fd=open(filename, O_RDONLY | O_NONBLOCK))<0)
 {
  perror("open");
  _exit(1);
 }
 event.events=EPOLLIN;
 event.data.fd=fd;
 if(epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &event))
 {
  perror("epoll_ctl(add)");
  _exit(1);
 }
}

int main(void)
{
 char buf[4096];
 int i,rc;
 int epfd;
 struct epoll_event events[2];
 int num,numfds;
 epfd=epoll_create(2);
 if(epfd<0)
 {
  perror("epoll_create");
  return 1;
 }
 addevent(epfd,"p1");
 addevent(epfd,"p2");
 numfds=2;
 while(numfds)
 {
  if((num=epoll_wait(epfd,events,sizeof(events)/sizeof(*events),-1))<=0)
  {
   perror("epoll_wait");
   return 1;
  }
  for(i=0;i  {
   rc=read(events[i].data.fd,buf,sizeof(buf)-1);
   if(rc<0)
   {
    perror("read");
    return 1;
   }
   else if(!rc)
   {
    if(epoll_ctl(epfd, EPOLL_CTL_DEL,events[i].data.fd, &events[i]))
    {
     perror("epoll_ctl(del)");
     return 1;
    }
    close(events[i].data.fd);
    numfds--;
   }
   else
   {
    buf[rc]='\0';
    printf("read: %s",buf);
   }
  }
 }
 close(epfd);
 return 0;
}

*read和write的代替
#include
struct iovec
{
 void * iov_base; //指向缓冲区的地址
 void * iov_len;  //指向缓冲区的长度(字符长度)
}
int readv(int fd, const struct iovec * vector, size_t count);
int writev(int fd, const struct iovec * vector, size_t count);

例子:

#include <unistd.h>
#include <stdio.h>
#include <sys/uio.h>

int main(void)
{
 struct iovec buffers[3];
 buffers[0].iov_base="hello";
 buffers[0].iov_len=5;
 buffers[1].iov_base=" ";
 buffers[1].iov_len=3;
 buffers[2].iov_base="world\n";
 buffers[2].iov_len=6;

 writev(1,buffers,3);
 return 0;
}

阅读(1888) | 评论(0) | 转发(0) |
0

上一篇:bounce buffer

下一篇:了解openvms ,alpha,安腾

给主人留下些什么吧!~~