多路转接模型之poll

来源:互联网 发布:水果音乐软件下载 编辑:程序博客网 时间:2024/06/05 18:31

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 | POLLRDBANDPOLLRDNORM-数据可读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 1024int 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 \n",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 \n");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 \n");close(conn_st);client[i].fd=-1;}}else if(rv==0){printf("close client \n");close(conn_st);client[i].fd=-1;}else{printf("recv from client:%s \n",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 \n",argv[0]);return 0;}int port=atoi(argv[1]);if(port==0){printf("port error \n");return 0;}printf("start server \n");run_server(port);return 0;}



0 0