上一篇文章我们谈了用select编写一个服务器这篇文章我们就用poll编写一个服务器,其实内容大同小异先列出poll的相关API:
第一个参数是一个指向 pollfd的结构体的指针下面我们列出结构体中的内容:
结构体中包含文件描述符和文件的操作
第二个参数是文件描述符的个数。第三个参数是等待时间,是以毫秒问单位。
下面给出poll服务器的代码:
#include<stdio.h>
#include<stdlib.h>
#include<sys/socket.h>
#include<sys/types.h>
#include<arpa/inet.h>
#include<netinet/in.h>
#include<poll.h>
#include<unistd.h>
#include<string.h>
#define POLLFD_SIZE 1024
void pd_action(int index);
struct pollfd pd[POLLFD_SIZE];
static void usage(char* proc)
{
printf("usage:%s[ip][port]\n",proc);
}
int startup(char* ip,int port)
{
int sock=socket(AF_INET,SOCK_STREAM,0);
if(sock<0)
{
perror("socket");
exit(2);
}
int opt =1;
setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt));
struct sockaddr_in server_addr;
server_addr.sin_family=AF_INET;
server_addr.sin_port=htons(port);
server_addr.sin_addr.s_addr=inet_addr(ip);
if(bind(sock,(struct sockaddr*)&server_addr,sizeof(server_addr))<0)
{
perror("bind");
exit(3);
}
if(listen(sock,10)<0)
{
perror("listen");
exit(4);
}
return sock;
}
int main(int argc,char* argv[])
{
if(argc!=3)
{
usage(argv[0]);
exit(1);
}
int listen_sock=startup(argv[1],atoi(argv[2]));
pd[0].fd=listen_sock;
pd[0].events=POLLIN;
int i=1;
for(;i<POLLFD_SIZE;++i)
{
pd[i].fd=-1;
}
int _timeout=100000;
int repd=-1;
while(1)
{
repd=poll(pd,POLLFD_SIZE,_timeout);
switch(repd)
{
case 0:
printf("timeout...");
break;
case -1:
perror("poll");
break;
default:
{
int j=0;
for(j=0;j<POLLFD_SIZE;++j)
{
if(j==0&& pd[j].revents & POLLIN)
{
struct sockaddr_in client_addr;
socklen_t len=sizeof(client_addr);
int new_sock=accept(listen_sock,(struct sockaddr*)&client_addr,&len);
if(new_sock<0)
{
perror("accept");
exit(5);
}
printf("new client connected!\n");
fflush(stdout);
int k=1;
for(;k<POLLFD_SIZE;++k)
{
if(pd[k].fd==-1)
{
pd[k].fd=new_sock;
pd[k].events=POLLIN;
break;
}
else if(k==POLLFD_SIZE)
{
printf("内存已满!");
return;
}
}
}
else if(pd[j].fd!=0)
{
pd_action(j);
}
}
break;
}
}
}
return 0;
}
void pd_action(int index)
{
if(pd[index].revents & POLLIN)
{
char buff[1024];
memset(buff,0,sizeof(buff));
int s=read(pd[index].fd,buff,sizeof(buff)-1);
if(s>0)
{
buff[s]=0;
printf("client say:%s",buff);
fflush(stdout);
pd[index].events=POLLOUT;
}
else if(s<=0)
{
printf("Client Quit!\n");
fflush(stdout);
close(pd[index].fd);
pd[index].fd=-1;
}
}
else if(pd[index].revents & POLLOUT)
{
const char*msg="HTTP/1.1 200 OK\r\n\r\n<html><br/><h1>hello poll</h1></html>";
write(pd[index].fd,msg,strlen(msg));
pd[index].events=POLLIN;
}
}
因为服务器返回值是一个HTML的字符串所以这个服务器也可以用浏览器直接打开。
poll服务器的优点:
高效;文件描述符的个数没有上限,解决了select句柄有限的问题
缺点:
包含大量文件描述符的数组被整体复制于用户态和内核的地址空间之间,而不论这些文件描述符是否就绪,它的开销随着文件描述符数量的增加而线性增大。
欢迎指正;