poll系统调用

来源:互联网 发布:sql基础教程 编辑:程序博客网 时间:2024/06/01 07:40

        上节所述的IO复用中的select函数基本机制与poll基本一致,都是采用轮询的方式来查看我们所关注的文件描述符。

        一:下面我们首先介绍一下poll与select的区别:

            1. poll将描述符和事件统一到一个结构体中

            2. poll能够同时监听的文件描述符比select多

            3. poll事件类型比select多:包括优先级带数据可读,高优先级数据可读等事件类型

         二:poll系统调用

               #include<poll.h>

               int poll(struct pollfd* fds,nfds_t nfds,int tinmeout)

               1. 参数意义

                   第一个参数是一个pollfd结构类型的数组,它指定所有我们感兴趣的文件描述符上发生的可读,可写和异常事件等,pollfd结构体定义如下:“

                    struct pollfd

                    {

                         int fd;   //文件描述符

                         short events; //注册的事件,即关注的事件,如果有多个关注事件,可以按位或

                         short revents; //实际发生的事情,由内核来填充

                    };

                   第二个参数指定被监听的事件集合fds的大小;第三个参数为poll的超时时间,单位为毫秒。

              2. 返回值

                  返回值为0,表示超时,返回值为负数,表示出错,大于0,表示就绪的文件描述符数

              3. 基本原理

                   poll函数与select函数原理基本相同,只是它不需要每次将位集合清0,因为其有一个结构体数组,每个结构体数组都包含一个文件描述符和关注事件以及实际发生的事件,调用poll函数之后,内核会将当前正在监听的该文件描述符上的实际发生的事件存储在revents中,我们只需要核对该文件描述符上实际发生的事件是否是我们想要关注的事件,如果是,则判断是否是当前我们关心的监听文件描述符,如果是,执行相应的业务操作进行客户端连接,完成三次握手,否则,就有可能是客户端已经连接的文件描述符上的数据已经准备就绪,这时我们只需要调用recv函数进行读取数据就可以了。

             4. 遇到每次只接收一个字符的情况,处理方式

                  当每次只接收读取一个字符时,而客户端还是每次输入一个字符串时,那么服务器端就会调用poll一共字符串的长度加1次(包含回车),最终服务器端的终端上会主次将输入的字符串以一次一个字符的形式打印显示出来,再输出一个回车字符。原因在于内核会一直提醒我们该文件描述符上有数据准备就绪,一直等到我们将所有数据处理完成后才停止。

            5. 服务器端代码如下:

              #include <stdio.h>
              #include <stdlib.h>
              #include <assert.h>
              #include <unistd.h>
              #include <string.h>
              #include <sys/socket.h>
              #include <arpa/inet.h>
              #include <netinet/in.h>
              #include<sys/select.h>
              #include<sys/time.h>
              #include<sys/types.h>
              #include<poll.h>
              #define MAX 30

             int create_socket();
             void fds_init(struct pollfd fds[])
             {
                     int i=0;
                     for(;i<MAX;++i)
                      {
                            fds[i].fd=-1;
                            fds[i].events=0;
                            fds[i].revents=0;
                      }
            }
            void fds_add(struct pollfd fds[],int fd)
            {
                       int i=0;
                       for(;i<MAX;++i)
                        {
                            if(fds[i].fd==-1)
                           {
                                     fds[i].fd=fd;
                                     fds[i].events=POLLIN;//read events
                                     break;
                          }
                      }
           }


            void fds_clr(struct pollfd fds[],int fd)
            {
                   int i=0;
                   for(;i<MAX;++i)
                   {
                      if(fds[i].fd==fd)
                      {
                               fds[i].fd=-1;
                               fds[i].events=0;
                                 break;
                      }
                  }
           }
     

          int main()
          {
                  int sockfd=create_socket();
                  assert(sockfd!=-1);
 
                  struct pollfd fds[MAX];
                  fds_init(fds);
               fds_add(fds,sockfd);
                  while(1)
                   {
                        int n=poll(fds,MAX,5000);
                       if(n==-1)
                       {
                              perror("poll error\n");
                              continue;
                        }
                        else if(n==0)
                       {
                                 printf("time out\n");
                                 continue;
                         }
                         else
                         {
                                int i=0;
                               for(;i<MAX;++i)
                                {
                                          if(fds[i].fd==-1)
                                         {
                                                continue;
                                         }
                                         if(fds[i].revents & POLLIN)
                                        {
                                                      if(fds[i].fd==sockfd)
                                                      {
                                                               struct sockaddr_in caddr;
                                                                int len=sizeof(caddr);
   
                                                                int c=accept(sockfd,(struct sockaddr*)&caddr,&len);
                                                                if(c<0)
                                                                {
                                                                           continue;
                                                                }
                                                                printf("accept ::c=%d\n",c);
                                                               fds_add(fds,c);
                                                         }
                                                       else
                                                        {
                                                                  char buff[128]={0};
                                                                  if(recv(fds[i].fd,buff,127,0)<=0)//why we can not read many times?because once no data,the recv will block,can not over
                                                                 {
                                                                           printf("one client over\n");
                                                                            close(fds[i].fd);
                                                                            fds_clr(fds,fds[i].fd);
                                                                           continue;
                                                                 }
                                                                printf("read(%d)=%s\n",fds[i].fd,buff);
                                                                 send(fds[i].fd,"ok",2,0);
                                                        }
                                                  }
                                          }
                                     }
                               }
                   }
               

               int create_socket()
               {
                      int sockfd=socket(AF_INET,SOCK_STREAM,0);
                      assert(sockfd!=-1);

                      struct sockaddr_in saddr;
                      memset(&saddr,0,sizeof(saddr));
                      saddr.sin_family=AF_INET;
                      saddr.sin_port=htons(6000);
                      saddr.sin_addr.s_addr=inet_addr("192.168.31.44");

                      int res = bind(sockfd,(struct sockaddr *)&saddr,sizeof(saddr));
                      assert(res!=-1);

                      listen(sockfd,5);
                      return sockfd;
                }

                    

原创粉丝点击