I/O多路转接之poll

来源:互联网 发布:牙齿矫正知乎 编辑:程序博客网 时间:2024/05/16 13:41

poll采用了一个单独的结构体pollfd数组,由fds指针指向这个组。pollfd结构体定义如下:
struct pollfd {
int fd; //文件描述符
short events; //当下文件描述符关心的事件
short revents; //文件描述符关心的事件就绪
};
每一个pollfd结构体指定了一个被监视的文件描述符,可以传递多个结构体,指示poll()监视多个文件描述符。每个结构体的events域是监视该文件描述符关心的事件,由用户来设置这个域。revents域是文件描述符的关心事件发生了。内核在调用返回时设置这个域。events域中请求的任何事件都可能在revents域中返回。
函数原型:int poll (struct pollfd *__fds, nfds_t __nfds, int __timeout);
参数依次为: 结构体数组、有效文件描述符个数、超时时间

poll优点
1、poll() 不要求开发者计算最大文件描述符加一的大小。
2、poll() 在应付大数目的文件描述符的时候相比于select速度更快 。
3、它没有最大连接数的限制,原因是它是基于链表来存储的。
poll缺点
1、大量的fd的数组被整体复制于用户态和内核地址空间之间,而不管这样的复制是不是有意义。
2、与select一样,poll返回后,需要轮询pollfd来获取就绪的描述符。

使用poll监控输入输出

#include<stdio.h>#include<poll.h>#include<stdlib.h>#include<string.h>int main(int argc,char *argv[]){    struct pollfd _poll[1];    _poll[0].fd=0;    _poll[0].events=POLLIN;    _poll[0].revents=0;    int timeout=3000;    int i=0;    char buf[1024];while(1){    switch(poll(_poll,1,timeout))    {        case 0:            printf("timeout");            break;        case -1:            printf("poll");            break;        default:            {                for(i=0;i<2;i++)                {             if((_poll[0].fd==0)&&(_poll[0].revents)&POLLIN)             {              ssize_t s=read(0,buf,sizeof(buf)-1);              if(s>0)              {               buf[s]=0;               if(strncmp(buf,"hello poll",10)==0)               {                close(_poll[i].fd);                  return 1;               }               printf("ecjo:%s\n",buf);              }             }                }            }            break;    }}return 0;}

使用poll实现一个服务器;

#include<stdio.h>#include<stdlib.h>#include<poll.h>#include<unistd.h>#include<sys/types.h>#include<sys/socket.h>#include<arpa/inet.h>#include<netinet/in.h>#include<string.h>static void usage(char *proc){ printf("usage:%s [local_ip] [local_port]\n",proc);}int startup(char* _ip,int _port) {    //create socket  int sock=socket(AF_INET,SOCK_STREAM,0);  if(sock<0)  {    perror("socket");    return 2;  }  //port multiplexing  int flg=1;   setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,&flg,sizeof(flg));  struct sockaddr_in local;  local.sin_family=AF_INET;  local.sin_addr.s_addr=inet_addr(_ip);  local.sin_port=htons(_port);  //bind  if(bind(sock,(struct sockaddr*)&local,sizeof(local))<0)  {    perror("bind");    return 3;  }  //listen  if(listen(sock,10)<0)  {   perror("listen");   return 4;  }  return sock;}int main(int argc,char *argv[]){    if(argc!=3)    {      usage(argv[0]);      return 1;    }    int listen_sock=startup(argv[1],atoi(argv[2]));    struct pollfd fd_set[2];    fd_set[0].fd=listen_sock;    fd_set[0].events=POLLIN;    fd_set[0].revents=0;    int timeout=2000;    int n=sizeof(fd_set)/sizeof(fd_set[0]);    struct sockaddr_in client;    socklen_t len=sizeof(client);    int i=1;    for(;i<n;i++)    {     fd_set[i].fd=-1;    }    int maxfd=0;    while(1)    {      switch(poll(fd_set,maxfd+1,timeout))      {          case 0:              printf("timeout..\n");              break;          case -1:              printf("poll");              break;          default:              {                  for(i=0;i<n;i++)                  {                    if((fd_set[i].fd==listen_sock)&& \                            (fd_set[i].revents)&POLLIN)                    {                      int new_sock=accept(listen_sock,\                              (struct sockaddr*)&client,&len);                      if(new_sock<0)                      {                        perror("accept");                        continue;                      }                      printf("get a new client\n");                      int j=0;                      for(j=0;j<n;j++)                      {                       if(fd_set[j].fd==-1)                       {                         fd_set[j].fd=new_sock;                         fd_set[j].events=POLLIN;                         fd_set[j].revents=0;                         break;                       }                    }                         if(j==n)                       {                         close(new_sock);                       }                       if(j>maxfd)                       {                         maxfd=j;                       }                    }                    else if((fd_set[i].fd>0)&& (fd_set[i].revents)&POLLIN)                    {                     char buf[1024];                     ssize_t s=read(fd_set[i].fd,buf,sizeof(buf)-1);                     if(s>0)                     {                      buf[s]='\0';                      printf("client:  %s\n",buf);                      write(fd_set[i].fd,buf,strlen(buf));                     }                     else if(s==0)                       {                            close(fd_set[i].fd);                            int p=1;                            for(;p<n;i++)                            {                            if((fd_set[p].fd!=-1)&&(p!=i))                            {                             int temp=fd_set[i].fd;                             fd_set[i].fd=fd_set[p].fd;                             fd_set[p].fd=temp;                            }                       }                    }                  }              }              }              break;      }    } return 0;}
原创粉丝点击