I/O复用(二)——poll

本文详细解析了poll系统调用的工作原理,包括其参数解释、事件类型及应用实例。对比select,poll提供了更细致的事件分类,适用于高效地轮询多个文件描述符的就绪状态。

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

之前我们介绍select 的时候,我们已经说过了I/O复用的相关概念,话不多说,今天我们就直接来看I/O复用的另一个系统调用:poll。

poll系统调用和select相似,也是在指定的时间内轮询一定量的文件描述符,以测试其中是否有就绪事件。原型如下:

(1)fd参数是一个polled结构体类型的数组,原型如下:

 

event成员告知poll监听哪些事件,也就是用户感兴趣的事件,是一系列的按位或;而revents成员则是由内核修改的,通知程序fd上实际发生的事件,poll支持的事件可以参照下表:

 

 

可以看出poll将POLLIN事件和POLLOUT事件划分的更加详细了,以区别对待普通数据和优先数据,可惜Linux不完全支持。

之前select中我们判断客户端是否断开连接通常是用recv的返回值是否等于0来判断,事实上这样不是特别靠谱的,所以呢,对于断开连接的情况,GNU就为poll增加了一个POLLRDHUP事件,它负责在socket上接收对端关闭连接触发,但是这个事件触发必然会引起EPLLIN事件,一点一定要注意啊反正第一次我是忘了,否则在编写代码时有可能会出错很难办。另外,使用EPOLLRDHUP事件需要定义_GNU_SOURCE。

 (2)nfds参数指定被监听事件集合fds的大小

(3)timeout参数指定poll的超时值,当timeout为-1时,poll调用永久阻塞,直到事件发生。

另外,poll调用的系统返回值含义与select相同。

poll的应用(代码实现)

#define _GNU_SOURCE//千万要记得啊
#include<stdlib.h>
#include<stdio.h>
#include<string.h>
#include<assert.h>
#include<arpa/inet.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<sys/select.h>
#include<poll.h>

void Init(struct pollfd *fds)
{
	int i=0;
	for(;i<100;i++)
	{
		fds[i].fd=-1;
		fds[i].events=0;
		fds[i].revents=0;
	}
}
void Insert(struct pollfd *fds,int fd,short event)
{
	int i=0;
	for(;i<100;i++)
	{
		if(fds[i].fd==-1)
		{
			fds[i].fd=fd;
			fds[i].events=event;
			break;	
		}
	}
}
void Delete(struct pollfd *fds,int fd)
{
	int i=0;
	for(;i<100;i++)
	{
		if(fds[i].fd==fd)
		{
			fds[i].fd=-1;
			fds[i].events=0;
			break;
		}
	}
}
int main()
{
	int sockfd=socket(AF_INET,SOCK_STREAM,0);
	assert(sockfd!=-1);
	struct sockaddr_in ser,cli;
	memset(&ser,0,sizeof(ser));
	ser.sin_family=AF_INET;
	ser.sin_port=htons(6000);
	ser.sin_addr.s_addr=inet_addr("127.0.0.1");
	int res=bind(sockfd,(struct sockaddr*)&ser,sizeof(ser));
	assert(res !=-1);
	listen(sockfd,5);
	struct pollfd fds[100];
	Init(fds);
	Insert(fds,sockfd,POLLIN);
	while(1)
	{
		int n=poll(fds,100,-1);
		if(n<=0)
		{
			printf("erron\n");
			continue;
		}
		int i=0;
		for(;i<100;i++)
		{
			if(fds[i].fd!=-1)
			{
				int fd=fds[i].fd;
               //先处理关闭连接事件,因为它也引起的POLLIN事件
				if(fds[i].revents & POLLRDHUP)
				{
					close(fd);
					Delete(fds,fd);
				}
				else if(fds[i].revents & POLLIN)
				{
					if(fd==sockfd)
					{
						int len =sizeof(cli);
						int c=accept(fd,(struct sockaddr*)&cli,&len);
						if(c<0)
						{
							continue;
						}
						Insert(fds,c,POLLIN|POLLRDHUP);
					}
					else
					{
						char buff[128]={0};
						recv(fd,buff,127,0);
						printf("%d:%s\n",fd,buff);
						send(fd,"ok",2,0);
					}
				}
			}
		}

	}
}

 

 

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值