I/O多路转接之poll

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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值