Linux关于IO复用(poll模型)

POLL函数概念

Poll函数和select类似,但它是用文件描述符而不是条件的类型来组织信息的. 也就是说,一个文件描述符的可能事件都存储在struct pollfd中.与之相反,select用事件的类型来组织信息,而且读,写和错误情况都有独立的描述符掩码.poll函数是POSIX:XSI扩展的一部分,它起源于UNIX System V

函数poll原型

包含头文件<poll.h> 功能:与select函数功能相同 原型: int poll(struct pollfd *fdarray,unsigned long nfds,int timeout); 参数 fdarray是一个pollfd的机构体数组用来表示表示文件描述符的监视信息 nfds参数给出了要监视的描述符数目 timeout参数是一个用豪秒表示的时间,是poll在返回前没有接收事件是应等待的时间,如果timeout的值为-1,poll就永远不会超时.如果整数值为32个比特,那么最大超时周期约为30分钟 返回值:准备好描述字的个数,0-超时,1-出错

Pollfd结构体

fd是文件描述符值 event和revents是通过代表各种事件的标准符进行逻辑或运算构建而成的                  

Struct pollfd         {          

 int fd;            

short events;   //感兴趣的事件          

 short revents;  //fd上触发的事情     

    }

Poll函数事件标志

 事件标志符

    含义

POLLIN

无阻塞地读除了具有高优先级的数据之外的数据

POLLRONORM

无阻塞地读常规数据

POLLRDBAND

无阻塞地读具有优先级的数据

POLLOUT

无阻塞的写常规数据

Poll函数实现

与之前的select实现基本一致,实现c/s架构

首先服务器:

#include <stdio.h>  
#include <stdlib.h>  
#include <string.h>  
#include <sys/types.h>  
#include <sys/wait.h>
#include <sys/socket.h>  
#include <netinet/in.h> /* for struct sockaddr_in*/  
#include <sys/errno.h>  
#include <signal.h> 
#include <sys/select.h>
#include <poll.h>

//关于IO复用服务器的poll

#define LISTEN_SIZE 1024
void error_exit(char *name)
{
   perror(name);
   exit(-1);
}
int main(int argc,char *argv[])
{
   int sockfd=socket(AF_INET,SOCK_STREAM,0);
   if(sockfd<0)
   {
        error_exit("create error");
   }
   //绑定地址(ip和端口号)
   struct sockaddr_in svraddr;
   memset(&svraddr,0,sizeof(svraddr));
   svraddr.sin_family=AF_INET;
   svraddr.sin_addr.s_addr=INADDR_ANY;
   //svraddr.sin_addr.s_addr=inet_addr("127.0.0.1");第二种写法
   svraddr.sin_port=htons(5555);
   int ret=bind(sockfd,(struct sockaddr*)&svraddr,sizeof(svraddr));
   if(ret<0)
   {
      error_exit("bind error");
   }
   //设置监听参数back login 半连接数最大
   ret=listen(sockfd,1024);
   if(ret<0)
   {
      error_exit("listen error");
   }
   //创建poll结构体
   struct pollfd pollfds[LISTEN_SIZE]={0};
   int i=0;
   for(;i<LISTEN_SIZE;i++)
   {
       pollfds[i].fd=-1;
   }
   pollfds[0].fd=sockfd;
   pollfds[0].events=POLLIN;
   struct sockaddr_in removeaddr;
   int addr_len=sizeof(removeaddr);
   char *buf[1024]={0};
   while(1)
   {
      int nevent=poll(pollfds,LISTEN_SIZE,-1);
      if(nevent==0)
      {
            printf("timeout\n");
            continue;
      }
      else if(nevent<0)
      {
            error_exit("poll error");
      }
      if(pollfds[0].revents&POLLIN)
      {
         int fd=accept(sockfd,(struct sockaddr *)&removeaddr,&addr_len);
         if(fd<0)
         {
             error_exit("accept error");
          }
          for(i=1;i<LISTEN_SIZE;i++)
          {
                if(pollfds[i].fd==-1)
                {
                   pollfds[i].fd=fd;
                   pollfds[i].events=POLLIN;
                   break;
                }
          }
          for(i=1;i<LISTEN_SIZE;i++)
          {
                if(pollfds[i].fd==-1)
                {
                    continue;
                } 
                 //判断是否为可读事件
                if(pollfds[i].revents&POLLIN)
                {
                    int rdsize=read(pollfds[i].fd,buf,1024);
                    if(rdsize<=0)
                    {
                        printf("close %d\n",pollfds[i].fd);
                        close(pollfds[i].fd);
                        pollfds[i].fd=-1;
                    }
                    else
                    {
                        printf("read buf =%s,fd=%d\n",buf,pollfds[i].fd);
                    }
                }
          }
      }
   }
}

客户端:

使用之前的代码,基本不变,贴上来

#include <stdio.h>  
#include <stdlib.h>  
#include <string.h>  
#include <sys/types.h>  
#include <sys/wait.h>
#include <sys/socket.h>  
#include <netinet/in.h> /* for struct sockaddr_in*/  
#include <sys/errno.h>  
#include <signal.h> 

//关于客户端的socket
void error_exit(char *name)
{
   perror(name);
   exit(-1);
}
int main(int argc,char *argv[])
{
   if(argc<3)
   {
        printf("run program+ip+port\n");
        return-1;
   }
   int sockfd=socket(AF_INET,SOCK_STREAM,0);
   if(sockfd<0)
   {
        error_exit("create error");
   }
   //连接服务器,设置服务器的地址(ip和端口)
   struct sockaddr_in svraddr;
   memset(&svraddr,0,sizeof(svraddr));
   svraddr.sin_family=AF_INET;
   svraddr.sin_addr.s_addr= inet_addr(argv[1]);
   svraddr.sin_port=htons(atoi(argv[2]));
   int ret =connect(sockfd,(struct sockaddr *)&svraddr,sizeof(svraddr));
   if(ret<0)
   {
      error_exit("connect error");
   }

   write(sockfd,"hello",strlen("hello"));
   sleep(5); 
   close(sockfd);
   return 0;
}

结果:

客户端执行后台操作

服务器接受到的结果

总结:相比较之前的select函数,poll没有FD_SETSIZE这个限制,poll的出现可以解决select的fd数量限制

猜你喜欢

转载自blog.csdn.net/Gaodes/article/details/82823577