zoukankan      html  css  js  c++  java
  • 多路转接模型之poll

    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;
    }
    



  • 相关阅读:
    pyinstaller 打包后无法运行
    Android Uiautomator2 gradlew 坑
    JNDI 在 J2EE 中的角色
    23种设计模式
    Struts2工作原理
    SpringMVC工作原理
    堆内存设置
    安装和使用 memcached
    SQL面试题及答案
    30多条mysql数据库优化方法,千万级数据库记录查询轻松解决
  • 原文地址:https://www.cnblogs.com/mfmdaoyou/p/6845195.html
Copyright © 2011-2022 走看看