码迷,mamicode.com
首页 > 其他好文 > 详细

多路I/O poll编写服务器

时间:2016-05-28 23:33:42      阅读:391      评论:0      收藏:0      [点我收藏+]

标签:poll 模型

一.poll (多路复用I/O poll)

 和select()函数一样,poll函数也可以执行多路I/O复用,但poll与select相比,没有像select那样构建结构体的三个数组(针对每一个条件分别有一个数组:读事件,写事件,异常),然后检查从0到nfds每个文件描述符。poll采用了一个单独的结构体pollfd数组,由fds指针指向这个组。pollfd结构体定义如下:

#include <sys/poll.h>

struct pollfd {
int fd; //文件描述符
short events; //当下文件描述符关心的事件
short revents; //文件描述符关心的事件就绪
};

每一个pollfd结构体指定了一个被监视的文件描述符,可以传递多个结构体,指示poll()监视多个文件描述符。每个结构体的events域是监视该文件描述符关心的事件,由用户来设置这个域。revents域是文件描述符的关心事件发生了。内核在调用返回时设置这个域。events域中请求的任何事件都可能在revents域中返回

函数原型:int poll (struct pollfd *__fds, nfds_t __nfds, int __timeout);

参数依次为: 结构体数组、有效文件描述符个数、超时时间


1>示例1使用poll监控输入输出

  程序代码:

  1 #include<stdio.h>
  2 #include<errno.h>
  3 #include<poll.h>
  4 #include<string.h>
  5 int main()
  6 {
  7   struct pollfd fd_set[1];//定义一个结构体数组
  8   fd_set[0].fd=0;
  9   fd_set[0].events=POLLIN;//可读
 10   fd_set[0].revents=0;
 11   int timeout=5000;
 12    while(1)
 13    {
 14      switch(poll(fd_set,1,timeout))
 15      {
 16        case -1://chucuo
 17        perror("poll");
 18        break;
 19         case 0://timeout
 20         printf("poll timeout\n");
 21         break;
 22        default: //normal
 23        {
24           if((fd_set[0].fd==0)&&((fd_set[0].revents)&POLLIN))
 25              {
 26                //DATA IS READY
 27                char buf[1024];
 28                memset(buf,‘\0‘,sizeof(buf));
 29                ssize_tsize=read(0,buf,sizeof(buf)-1);
 30                if(size>0)
 31                   {
 32                     buf[size]=‘\0‘;
 33                    printf("echo->  %s",buf);
 34
 35                    }
 36                     else if(size==0)
 37                     {
 38                        printf("closing.........\n");
 39                      }
 40
 41              }
 42           }
 43           break;
 44          }
 45        }
 46     return 0;

程序结果:

技术分享

2>示例2搭建poll服务器

程序代码:

 // poll_server.c
  
  1 #include<stdio.h>
  2 #include<errno.h>
  3 #include<poll.h>
  4 #include<string.h>
  5 #include<sys/types.h>
  6 #include<arpa/inet.h>
  7 #include<netinet/in.h>
  8 #include<sys/socket.h>
  9 #include<stdlib.h>
 10 
 11 static void usage(char *proc)
 12 {
 13    printf("usage: %s [ip] [port] ",proc);
 14 }
 15 
 16 static int start(int port,char *ip)
 17 {
 18     int sock=socket(AF_INET,SOCK_STREAM,0);
 19     if(sock<0)
 20     {
 21       perror("socket");
 22        exit(1);
 23     }
 24     struct sockaddr_in local;
 25     local.sin_family=AF_INET;
 26     local.sin_port=htons(port);
 27     local.sin_addr.s_addr=inet_addr(ip);
 28     if(bind(sock,(struct sockaddr*)&local,sizeof(local))<0)
 29      {
 30       perror("bind");
 31       exit(2);
 32      }
 33     if(listen(sock,5)<0)
 34      {
 35        perror("listen");
 36        exit(3);
 37      }
 38      return sock;
 39 }
 40 int main(int argc,char*argv[])
 41 {
 42   if(argc!=3)
 43   {
 44      usage(argv[0]);
 45      return 1;
 46   }
 47   int port=atoi(argv[2]);
 48   char* ip=argv[1];
 49   int listen_sock=start(port,ip);
 50   struct pollfd fd_set[2];
 51   fd_set[0].fd=listen_sock;
 52   fd_set[0].events=POLLIN;
 53   fd_set[0].revents=0;
 54   int timeout=8000;
 55   int fd_setn=sizeof(fd_set)/sizeof(fd_set[0]);
 56   struct sockaddr_in client;
 57   socklen_t len=sizeof(client);
 58   int i=1;
 59   for(;i<fd_setn;++i)
 60    {
 61      fd_set[i].fd=-1;
 62    }
 63 
 64   int max_fd=0;
 65 while(1)
 66  {
 67 
 68      switch(poll(fd_set,max_fd+1,timeout))
 69      {
 70        case -1://chucuo
 71        perror("poll");
 72        break;
 73         case 0://timeout
 74         printf("poll timeout\n");
 75         break;
 76        default: //normal
 77        {
 78           for(i=0;i<fd_setn;++i)
 79           {//listen_sock时,接收连接请求
 80            if((fd_set[i].fd==listen_sock)&&((fd_set[i].revents)&POLLIN))
 81              {
 82             intnew_sock=accept(listen_sock,(struct sockaddr*)&client,&len);
 83                if(new_sock<0)
 84                 {
 85                   perror("accept");
 86                   continue;
 87                 }
 88                printf("get a connect......\n");
 89                 int j=0;
 90                for(j=0;j<fd_setn;++j)
 91                  {
 92                   if(fd_set[j].fd==-1)
 93                      {   //将new_sock添加进去
 
 94                         fd_set[j].fd=new_sock;
 95                         fd_set[j].events=POLLIN;
 96                         fd_set[j].revents=0;
 97                         break;
 98                      }
 99                  }
100 
101                if(j==fd_setn)
102                 {
103                    close(new_sock);
104 
105             }
106                 if(j>max_fd)//有效文件描述符个数
107                   {
108                     max_fd=j;
109                    }
110                }
111                                 //可读数据
112                else if((fd_set[i].fd>0)&&((fd_set[i].revents)&POLLIN))
113                {
114 
115                   char buf[1024];
116                   ssize_t s=read(fd_set[i].fd,buf,sizeof(buf)-1);
117                   if(s>0)//读成功
118                    {
119                     buf[s]=‘\0‘;
120                     printf("client#:  %s\n",buf);
121                     write(fd_set[i].fd,buf,strlen(buf));
122 
123                     }
124                    else if(s==0)
125                     {
126                       close(fd_set[i].fd);
127                       int xj=1;
                                                 //将其置为无效状态

128                       for(;xj<fd_setn;++i)
129                        {
130                           if(fd_set[xj].fd!=-1&&(xj!=i))
131                            {
132                             int tmp=fd_set[i].fd;
133                             fd_set[i].fd=fd_set[xj].fd;
134                             fd_set[xj].fd=tmp;
135                              }
136                           }
137                      }
138                    }
139 
140                 }
141 
142            }
143           break;
144          }
145 
146        }
147     return 0;
148 }
//poll_client.c
  1 #include<stdio.h>
  2 #include<errno.h>
  3 #include<poll.h>
  4 #include<string.h>
  5 #include<sys/types.h>
  6 #include<arpa/inet.h>
  7 #include<netinet/in.h>
  8 #include<sys/socket.h>
  9 #include<stdlib.h>
 10 
 11 static void usage(char *proc)
 12 {
 13    printf("usage: %s [ip] [port] ",proc);
 14 }
 15 
 16 
 17 int main(int argc, char*argv[])
 18 {
 19   if(argc!=3)
 20   {
 21      usage(argv[0]);
 22      return 1;
 23   }
 24   int port=atoi(argv[2]);
 25   char* ip=argv[1];
 26   int sock=socket(AF_INET,SOCK_STREAM,0);
 27   if(sock<0)
 28   {
 29       perror("socket");
 30       exit(1);
 31   }
 32    struct sockaddr_in remote;
 33    remote.sin_family=AF_INET;
 34    remote.sin_port=htons(port);
 35    remote.sin_addr.s_addr=inet_addr(ip);
 36       int ret=connect(sock,(struct sockaddr*)&remote,sizeof(remote));//请求连接
 37     if(ret<0)
 38   {
 39      perror("coonect");
 40      exit(3);
 41 
 42    }
 43    char buf[1024];
 44    while(1)
 45    {
 46      memset(buf,‘\0‘,sizeof(buf));
 47      printf("please enter: ");
  48      fflush(stdout);
  49      ssize_t s=read(0,buf,sizeof(buf)-1);
  50      if(s>0)
  51       {
  52        write(sock,buf,strlen(buf));
  53        }
        //回显消息
  54          ssize_t size=read(sock,buf,sizeof(buf)-1);
    55     {
    56       printf("server->client :%s\n",buf);
    57 
    58     }
    59    }
  56       printf("server->client :%s\n",buf);
  59    }
  60     close(sock);
  61     return 0;
  62 }

 程序结果:

技术分享

技术分享

poll总结:

1.poll与select一样实现需要自己不断轮询所有fd集合,直到设备就绪,期间可能要睡眠和唤醒多次交替。

2.poll与select一样每次调用都要把fd集合从用户态往内核态拷贝一次。

3.select,poll都是IO多路复用的机制。I/O多路复用就通过一种机制,可以监视多个描述符,一旦某个描述符就绪(一般是读就绪或者写就绪),能够通知程序进行相应的读写操作。但select,poll本质上都是同步I/O,因为他们都需要在读写事件就绪后自己负责进行读写,也就是说这个读写过程是阻塞的。





 

 






本文出自 “输出菱形图案” 博客,请务必保留此出处http://10541571.blog.51cto.com/10531571/1784067

多路I/O poll编写服务器

标签:poll 模型

原文地址:http://10541571.blog.51cto.com/10531571/1784067

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!