多路转接模型之poll

本文介绍如何利用poll系统调用在服务器端实现高效的数据读写监听,通过实例展示了创建监听套接字、接受客户端连接、读取并响应数据的基本流程。重点阐述了poll函数的使用方法及参数解释,包括监听事件、触发事件的表示和区别,以及如何通过poll系统调用优化服务器端性能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值