函数原型:
函数说明:该函数允许进程指示内核等待多个事件中的任何一个发生,并只在有一个或多个事件发生或经历一段指定的时间后才唤醒它。
参数说明:
fds:是一个struct pollfd结构类型的数组,用于存放需要检测其状态的Socket描述符;
每当调用这个函数之后,系统不会清空这个数组,操作起来比较方便;特别是对于socket连接比较多的情况下,在一定程度上可以提高处理的效率;这一点与select()函数不同,调用select()函数之后,select()函数会清空它所检测的socket描述符集合,导致每次调用select()之前都必须把socket描述符重新加入到待检测的集合中;因此,select()函数适合于只检测一个socket描述符的情况,而poll()函数适合于大量socket描述符的情况;
nfds:nfds_t类型的参数,用于标记数组fds中的结构体元素的总数量;
timeout:是poll函数阻塞的时间,单位:毫秒;
如果timeout==0,那么poll() 函数立即返回而不阻塞
如果timeout==INFTIM,那么poll() 函数会一直阻塞下去,直到所检测的socket描述符上的感兴趣的事件发生是才返回,如果感兴趣的事件永远不发生,那么poll()就会永远阻塞下去;
poll()函数会以轮询方式在timeout所指定的毫秒时间长度之后返回
返回值:
>0:数组fds中准备好读、写或出错状态的那些socket描述符的总数量;
==0:数组fds中没有任何socket描述符准备好读、写,或出错;此时poll超时,超时时间是timeout毫秒
-1: poll函数调用失败,同时会自动设置全局变量errno;
struct pollfd中event的设置参数:
实现IO复用:关心输入输出条件就绪
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<poll.h>
int main()
{
struct pollfd fds[2];
fds[0].fd=0;
fds[0].events=POLLIN;
fds[0].revents=0;
fds[1].fd=1;
fds[1].events=POLLOUT;
fds[1].revents=0;
char buf[1024];
ssize_t _s;
int i=0;
int timeout=5000;
while(1)
{
timeout=5000;
switch(poll(fds,2,timeout))
{
case -1://error
perror("poll");
break;
case 0://timeout
printf("time out\n");
break;
default:
{
for(i=0;i<2;++i)
{
if(fds[i].fd==0&&fds[i].revents&POLLIN)
{
_s=read(0,buf,sizeof(buf)-1);
if(_s>0)
{
buf[_s]=‘\0‘;
printf("%s",buf);
}
fds[i].revents=0;
}
// else if(fds[i].fd==1&&fds[i].revents&&POLLOUT)
// {
// strcpy(buf,"hello");
// printf("echo: %s",buf);
// fds[i].revents=0;
// }
}
}
break;
}
}
return 0;
}TCP通信:监听socket
server:
创建监听套接字并初始化:调用socket,bind,listen,唯一描述符是监听描述符初始化数据结构。
阻塞于select:select等待某个事件发生或新客户连接的建立或是数据,FIN或RST的到达。
accept新连接
如果监听套接字变为可读,那么已建立一个新的连接,我们调用accept并更新相应数据结构。使用fds数组中第一个未用项记录这个已连接描述符。
检查现有连接
对于每个现有客户连接,我们要测试其描述符是否在select返回描述符集中,如果是就从该客户读取一行文本,并回显,输出。如果该客户关闭了连接,那么read将返回0,更新数据结构。
poll与select不同在于描述符存储方式不同。
结构体数组的管理:当每次有需要关心的描述符时,将其放入结构体中,每次有无效的描述符后,在下次调用前需要把其从结构体清除。
//server:优质版
#include<stdio.h>
#include<sys/socket.h>
#include<sys/types.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<stdlib.h>
#include<poll.h>
#include<string.h>
#include<errno.h>
#define _BACKLOG_ 5
#define _SIZE_ 64
static void usage(const char* proc)
{
printf("%s [ip][port]\n",proc);
}
static int start(char* ip,int port)
{
//1.create a socket
int sock=socket(AF_INET,SOCK_STREAM,0);
if(sock<0)
{
perror("socket");
exit(1);
}
//2.bind
struct sockaddr_in local;
local.sin_family=AF_INET;
local.sin_port=htons(port);
local.sin_addr.s_addr=inet_addr(ip);
if(bind(sock,(struct sockaddr*)&local,sizeof(local))<0)
{
perror("bind");
exit(2);
}
//3.set listen state
if(listen(sock,_BACKLOG_)<0)
{
perror("listen");
exit(3);
}
return sock;
}
int main(int argc,char* argv[])
{
if(argc!=3)
{
usage(argv[0]);
return 1;
}
int _port=atoi(argv[2]);
char* _ip=argv[1];
//listen_sock_fd
int listen_sock=start(_ip,_port);
struct pollfd polls[_SIZE_];//struct pollfd arrays
int index=0;//effective fdnum
int timeout=5000;//millseconds
int i=0;//index
polls[0].fd=listen_sock;
polls[0].events=POLLIN;
polls[0].revents=0;
++index;
for(i=1;i<_SIZE_;++i)
{
polls[i].fd=-1;
}
char buf[1024];
ssize_t _s=0;
struct sockaddr_in remote;//accept
socklen_t len=sizeof(remote);
while(1)
{
//new start
timeout=5000;
int j=index;
i=0;
//消除struct pollfd中已不关心的描述符:前移,得到有效的最后一个元素下标
while(i<j)
{
while(i<j&&polls[i].fd!=-1)//从前面数第一个无效的
++i;
while(i<j&&polls[j].fd==-1)//从后面数第一个有效的
--j;
if(i<j)//复制fd
{
polls[i].fd=polls[j].fd;
polls[i].events=POLLIN;//可不需要,因为event参数不发生变化,本程序只监听读事件
polls[index].revents=0;
}
}
index=i;
//printf("%d",index);
//须保证polls是有序的
switch(poll(polls,index,timeout))//index表明最后一个关心的描述符在数组中下标+1=个数
{
case 0://timeout
printf("time out...\n");
break;
case -1://error
perror("poll");
break;
default://normal
{
for(i=0;i<index;++i)
{
if(polls[i].fd==listen_sock&&(polls[i].revents& POLLIN))
{
printf("get a connect\n");
int new_sock=accept(listen_sock, (struct sockaddr*)&remote,&len);
if(new_sock<0)
{
perror("accept");
continue;
}
if(index==_SIZE_)
{
printf("full");
close(new_sock);
return -1;
}
polls[index].fd=new_sock;
polls[index].events=POLLIN;
polls[index].revents=0;
++index;
}
else if(polls[i].fd>0&&(polls[i].revents& POLLIN))//read ready
{
_s=read(polls[i].fd,buf,sizeof(buf)-1);
if(_s>0)
{
buf[_s]=‘\0‘;
printf("client: %s",buf);
write(polls[i].fd,buf,strlen(buf));
polls[i].revents=0;
}
else if(_s==0)//client close
{
close(polls[i].fd);
polls[i].fd=-1;
printf("client is close\n");
}
}
else
{}
}
}
break;
}
}
for(i=0;i<_SIZE_;++i)
{
if(polls[i].fd!=-1)
close(polls[i].fd);
}
return 0;
}
//仿select版,用辅助数组存储,没有利用poll结构体的优点,event不清空,开销大
int main(int argc,char* argv[])
{
if(argc!=3)
{
usage(argv[0]);
return 1;
}
int _port=atoi(argv[2]);
char* _ip=argv[1];
//listen_sock_fd
int listen_sock=start(_ip,_port);
struct pollfd polls[_SIZE_];//struct pollfd arrays
int index=0;//effective fdnum
int timeout=5000;//millseconds
int i=0;//index
int fds[_SIZE_];
fds[0]=listen_sock;
for(i=1;i<_SIZE_;++i)
{
fds[i]=-1;
}
char buf[1024];
ssize_t _s=0;
struct sockaddr_in remote;//accept
socklen_t len=sizeof(remote);
while(1)
{
index=0;//new start
timeout=5000;
for(i=0;i<_SIZE_;++i)
{
polls[i].fd=-1;
}
for(i=0;i<_SIZE_;++i)
{
if(fds[i]!=-1)
{
polls[index].fd=fds[i];
polls[index].events=POLLIN;
polls[index].revents=0;
++index;
}
}
switch(poll(polls,index,timeout))
{
case 0://timeout
printf("time out...\n");
break;
case -1://error
perror("poll");
break;
default://normal
{
for(i=0;i<index;++i)
{
if(polls[i].fd==listen_sock&&(polls[i].revents& POLLIN))
{
printf("get a connect\n");
int new_sock=accept(listen_sock, (struct sockaddr*)&remote,&len);
if(new_sock<0)
{
perror("accept");
continue;
}
int j;
for(j=0;j<_SIZE_;++j)
{
if(fds[j]==-1)
{
fds[j]=new_sock;
break;
}
}
if(j==_SIZE_)
{
printf("full");
close(new_sock);
return -1;
}
polls[i].revents=0;//reset
}
else if(polls[i].fd>0&&(polls[i].revents& POLLIN))//read ready
{
_s=read(polls[i].fd,buf,sizeof(buf)-1);
if(_s>0)
{
buf[_s]=‘\0‘;
printf("client: %s",buf);
write(polls[i].fd,buf,strlen(buf));
}
else if(_s==0)//client close
{
close(polls[i].fd);
int j;
for(j=0;j<_SIZE_;++j)
{
if(fds[j]==polls[i].fd)
{
fds[j]=-1;
break;
}
}
printf("client is close\n");
}
}
else
{}
}
}
break;
}
}
for(i=0;i<_SIZE_;++i)
{
if(fds[i]!=-1)
close(fds[i]);
}
return 0;
}
//client:
#include<stdio.h>
#include<stdlib.h>
#include<errno.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<netinet/in.h>
#include<string.h>
void Usage(const char* proc)
{
printf("%s [ip][port]",proc);
}
int main(int argc,char* argv[])
{
if(argc!=3)
{
Usage(argv[0]);
return 1;
}
int client_sock=socket(AF_INET,SOCK_STREAM,0);
if(client_sock<0)
{
perror("socket");
return 1;
}
struct sockaddr_in client;
client.sin_family=AF_INET;
client.sin_port=htons(atoi(argv[2]));
client.sin_addr.s_addr=inet_addr(argv[1]);
char buf[1024];
ssize_t _s;
if(connect(client_sock,(struct sockaddr*)&client,sizeof(client))<0)
{
perror("connection");
return 2;
}
while(1)
{
printf("please enter:\n");
_s=read(0,buf,sizeof(buf)-1);
if(_s>0)
buf[_s]=‘\0‘;
if(strncmp(buf,"quit",4)==0)
{
printf("client is quit\n");
break;
}
write(client_sock,buf,_s);
_s=read(client_sock,buf,sizeof(buf)-1);
if(_s>0)
{
buf[_s]=‘\0‘;
printf("server->client: %s",buf);
}
}
close(client_sock);
return 0;
}运行截图:
本文出自 “小止” 博客,请务必保留此出处http://10541556.blog.51cto.com/10531556/1783601
原文:http://10541556.blog.51cto.com/10531556/1783601