您的位置:首页 > 其它

多路I/O poll编写服务器

2016-05-28 15:40 309 查看
一.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,因为他们都需要在读写事件就绪后自己负责进行读写,也就是说这个读写过程是阻塞的。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  模型 poll