poll系统调用和select类似。也是在指定时间内轮询一定数量的文件描写叙述符,以測试当中是否有就绪者。poll和select效率差点儿相同,仅仅是其使用接口相对简单些,poll不在局限于1024个文件描写叙述符。poll监听事件和触发事件分开,event表示监听事件。revents表示触发的事件。
相比select不用每一次都须要又一次设置监听事件。
#include <poll.h> int poll(struct pollfd *fds, nfds_t nfds, int timeout); //第一个參数是struct pollfd数组 struct pollfd { int fd; /* file descriptor */你要监控文件描写叙述符 short events; /* requested events */ 监听文件描写叙述符上的事件 传入參数由用户设置 short revents; /* returned events */监控文件描写叙述符事件返回值 传出參数由内核设置 }; POLLIN普通或带外优先数据可读,即POLLRDNORM | POLLRDBAND POLLRDNORM-数据可读 POLLRDBAND-优先级带数据可读 POLLPRI 高优先级可读数据 POLLOUT普通或带外数据可写 POLLWRNORM-数据可写 POLLWRBAND-优先级带数据可写 POLLERR 错误发生 POLLHUP 发生挂起 POLLNVAL 描写叙述字不是一个打开的文件 第二个參数。指结构体数组长度。 timeout 毫秒级等待 -1:堵塞等,#define INFTIM -1 Linux中未定义此宏 0:马上返回。不堵塞进程 >0:等待指定毫秒数,如当前系统时间精度不够毫秒,向上取值poll server端实例:
#include<stdio.h> #include<string.h> #include<poll.h> #include <sys/un.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include<errno.h> #define OPEN_MAX 1024 int create_listen(int port) { int listen_st,on; struct sockaddr_in s_addr; listen_st =socket(AF_INET,SOCK_STREAM,0); if(listen_st==-1) { perror("socket error "); return -1; } if(setsockopt(listen_st,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on))==-1) { perror("setsockopt error"); return -1; } s_addr.sin_port=htons(port); s_addr.sin_family=AF_INET; s_addr.sin_addr.s_addr=htonl(INADDR_ANY); if(bind(listen_st,(struct sockaddr*)&s_addr,sizeof(struct sockaddr_in))==-1) { perror("bind error"); return -1; } if (listen(listen_st, 5) == -1) // 设置文件描写叙述符具有监听的功能 { perror("listen error"); return -1; } return listen_st; } int run_server(int port) { int i,maxi,listen_st,conn_st,sockaddr_len; int nready; struct pollfd client[OPEN_MAX]; char buf[1024]; struct sockaddr_in c_addr; listen_st=create_listen(port); if(listen_st==-1) { return -1; } for(i=1;i<OPEN_MAX;i++) { client[i].fd=-1; } client[0].fd=listen_st; client[0].events=POLLIN; maxi=0; while(1) { nready = poll(client,maxi+1,-1);//poll 堵塞 if(nready<0) { perror("poll error"); break; } if((client[0].revents&POLLIN))//检測listen_st { sockaddr_len=sizeof(c_addr); conn_st=accept(listen_st,(struct sockaddr *)&c_addr,&sockaddr_len); printf("received form %s at port:%d ",inet_ntoa(c_addr.sin_addr),ntohs(c_addr.sin_port)); for(i=0;i<OPEN_MAX;i++) { if(client[i].fd<0) { client[i].fd=conn_st; client[i].events=POLLIN; break; } } if(i==OPEN_MAX) { printf("too many client "); close(conn_st); }else { if(i>maxi) //记录最大下标 { maxi=i; } } if(--nready==0) continue; } for(i=1;i<=maxi;i++) { if((conn_st=client[i].fd)<0) { continue; } if(client[i].revents&POLLIN) { memset(buf,0,sizeof(buf)); int rv=read(conn_st,buf,sizeof(buf)); if(rv<0) { if(errno==ECONNRESET)/* 当收到RST标志时*/ //这样的错误是因为客户端发过FIN ACk掉线了客服端进程已经结束了 服务端再发FIN 客户端会发送RST { printf("client aborted connection "); close(conn_st); client[i].fd=-1; } } else if(rv==0) { printf("close client "); close(conn_st); client[i].fd=-1; } else { printf("recv from client:%s ",buf); write(conn_st,buf,strlen(buf)); } if (--nready == 0) break; //就绪个数减一 } } } close(listen_st); return 0; } int main(int argc,char *argv[]) { if(argc<2) { printf("usage:%s port ",argv[0]); return 0; } int port=atoi(argv[1]); if(port==0) { printf("port error "); return 0; } printf("start server "); run_server(port); return 0; }