基本知识
poll的机制与select类似,与select在本质上没有多大差别;同样是轮询多个描述符,再根据描述符的状态进行处理;但是poll没有描述符数量的限制,这个与机器的上限有关;缺点与select类似即需要将大量的描述符从用户态复制至内核态;而不论这些文件描述符是否就绪,它的开销随着文件描述符数量的增加而线性增加。
函数
int poll(struct pollfd * pollfds,int timeout)
struct pollfd{
int fd ; //文件描述符
short events ; // 等待发生的 事件
short revents ;// 实际发生的事件
}
使用poll与select不一样,因为它们在合适的时候总是会从revents返回;POLLIN | POLLPRI 等价于select的读事件;POLLOUT|POLLWRBAND 等价于select的写事件;而POLLOUT等价于POLLWRNORM。注意这些表示并不是互斥的,它们可以被同时设置,表示这个文件描述符的读取和写入都会正常返回而不阻塞。timeout参数指定等待的毫秒数,无论I/O是否准备好,poll都会返回。timeout指定为负数表示无限超时,使poll一直挂起直到一个指定事件的发生。事件 events
- POLLIN 有数据可读
- POLLRDNORM 有普通数据可读
- POLLRDBAND 有优先数据可读
- POLLPRI 有紧急数据可读
- POLLOUT 数据可写
- POLLWRNORM 普通数据可写
- POLLWRBAND 优先数据可写
- POLLMSGSIGPOLL 消息可用
返回事件 revent
除了 事件外;还有- POLLERR 指定描述符发生错误
- POLLHUP 指定文件描述符挂起事件
- POLLNVAL 指定描述符非法
服务端代码
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define IPADDRESS "127.0.0.1"
#define PORT 9090
#define LISTENNUM 5
#define MAXOPEN 1000
/*
@funcation name : socketBind
@description: create socket and bind the address
@return
succ : listenfd
fail : -1
*/
int socketBind(char *ip,int port)
{
int listenfd ;
struct sockaddr_in servAddr ;
listenfd = socket(AF_INET,SOCK_STREAM,0) ;
if (listenfd < 0)
{
printf("listenfd create is error:%d\n",errno) ;
return -1 ;
}
bzero(&servAddr,sizeof(struct sockaddr_in)) ;
servAddr.sin_family= AF_INET ;
servAddr.sin_addr.s_addr = inet_addr(ip) ;
//inet_pton(AF_INET,ip,&servAddr.sin_addr) ;
servAddr.sin_port = htons(port) ;
int ret = bind(listenfd,(struct sockaddr*)&servAddr,sizeof(servAddr)) ;
if (ret < 0)
{
printf("bind is error:%d\n",errno) ;
return -1 ;
}
return listenfd ;
}
/*
@funcation name : handleConnection
@description: handle the client socket
@return
succ : 0
fail : -1
*/
int handleConnection(struct pollfd *connfds,int num)
{
int i , n ;
char buf[1024] ;
memset(buf,0,1024);
printf("deal the conn num:%d\n",num) ;
for(i = 1 ;i<=num;i++)
{
if(connfds[i].fd < 0)
continue ;
if(connfds[i].revents & POLLIN)
{
AGAIN:
n = read(connfds[i].fd,buf,1024) ;
if(n <0)
{
if (errno == EINTR)
{
goto AGAIN;
}
else
{
close(connfds[i].fd) ;
printf("close a conn index:%d,err:%d\n",i,errno) ;
connfds[i].fd = -1 ;
return -1;
}
}
else if(n==0)
{
printf("the socket is closed by the peer\n");
close(connfds[i].fd) ;
connfds[i].fd = -1 ;
}
else
{
buf[n] = '\0' ;
printf("recv data is :%s\n",buf) ;
write(connfds[i].fd,buf,n) ;
}
}
}
return 0 ;
}
/*
@funcation name : doPoll
@description: deal the poll of sockets;
this is main loop;
@return
succ : 0
fail : exit(-1) ;
*/
int doPoll(int listenfd)
{
int nReady = 0 ;
int maxI = 0 ;
int connfd =-1 ;
int i = 0;
struct sockaddr_in cliAddr ;
socklen_t cliAddrLen ;
struct pollfd clientfds[MAXOPEN] ;
cliAddrLen = sizeof(struct sockaddr) ;
memset(&cliAddr,0,sizeof(struct sockaddr_in)) ;
clientfds[0].fd = listenfd ;
clientfds[0].events = POLLIN ;
clientfds[0].revents = 0 ;
for (i = 1 ;i1 ;
}
for(;;)
{
printf("poll start...\n") ;
nReady = poll(clientfds,maxI+1,-1) ;
if(nReady ==-1)
{
if(errno == EINTR)
continue ;
else
exit(-1) ;
}
if(clientfds[0].revents & POLLIN)
{
printf("accept the connectin\n") ;
connfd = accept(listenfd,(struct sockaddr*)&cliAddr,&cliAddrLen) ;
printf("connfd:%d\n",connfd) ;
if (connfd < 0)
{
printf("error:%d\n",errno) ;
if (errno == EINTR)
{
continue ;
}
else
{
printf("some error:%d\n",errno) ;
exit(-1) ;
}
}
printf("accept a new client:%s,%d\n",inet_ntoa(cliAddr.sin_addr),ntohs(cliAddr.sin_port)) ;
for(i= 1 ;iif(clientfds[i].fd < 0)
{
clientfds[i].fd = connfd ;
break ;
}
}
if (i == MAXOPEN)
{
printf("too many clients.\n") ;
exit(-1) ;
}
clientfds[i].events = POLLIN ;
clientfds[i].revents = 0 ;
maxI = (i > maxI) ? i:maxI;
if(--nReady <= 0 )
continue ;
}
else
{
printf("deal a conn\n") ;
handleConnection(clientfds,maxI) ;
}
}
return 0 ;
}
/*
@funcation name : main
@description:
@return
succ : 0
fail : exit-1 )
*/
int main()
{
int listenfd ;
printf("init is ok\n") ;
listenfd = socketBind(IPADDRESS,PORT) ;
if (listenfd == -1)
{
return -1 ;
}
printf("create socket and bind is ok\n") ;
int ret = listen(listenfd,LISTENNUM) ;
if (ret < 0)
{
printf("listen is error\n") ;
exit(-1) ;
}
printf("deal the poll\n") ;
doPoll(listenfd) ;
printf("error\n") ;
close(listenfd) ;
return 0 ;
}
4 客户端代码
#include
#include
#include
#include
#include
#include
#include
#include
#define IP "127.0.0.1"
#define PORT 9090
#define MAXLINE 1024
int main()
{
struct sockaddr_in servAddr ;
socklen_t servAddrLen ;
int servfd = -1 ;
char buf[MAXLINE] = "Mr.luo" ;
AGAIN:
bzero(&servAddr,sizeof(struct sockaddr_in)) ;
servAddrLen = sizeof(struct sockaddr) ;
servAddr.sin_family = AF_INET ;
inet_pton(AF_INET,IP,&servAddr.sin_addr);
//servAddr.sin_addr.s_addr = inet_addr(IP) ;
servAddr.sin_port = htons(PORT) ;
servfd = socket(AF_INET,SOCK_STREAM,0) ;
int ret = connect(servfd,(struct sockaddr*)&servAddr,servAddrLen) ;
if (ret < 0)
{
if (errno == EINTR)
{
close(servfd) ;
goto AGAIN;
}
else
{
printf("error connect to serv:%d\n",errno) ;
close(servfd) ;
exit(-1) ;
}
}
sleep(1);
write(servfd,buf,strlen(buf)+1) ;
memset(buf,0,MAXLINE);
read(servfd,buf,MAXLINE) ;
printf("read data is :%s\n",buf) ;
close(servfd);
return 0 ;
}