I/O复用 —— poll

poll系统调用和select类似,也是在指定时间内轮询一定数量的文件描述符,以测试其中是否有就绪这poll的原型:#include<poll.h>int poll(struct pollfd* fds,nfds_t nfds,int timeout);fds参数是一个pollfd结构类型的数组它指定所有我们感兴趣的文件描述符上发生的可读、可写和异常等事件,定义如下:...
摘要由CSDN通过智能技术生成

poll系统调用和select类似,也是在指定时间内轮询一定数量的文件描述符,以测试其中是否有就绪这

poll的原型:

#include<poll.h>
int poll(struct pollfd* fds,nfds_t nfds,int timeout);

fds参数是一个pollfd结构类型的数组它指定所有我们感兴趣的文件描述符上发生的可读、可写和异常等事件,定义如下:

struct pollfd
{
    int fd;        //用户关注的文件描述符
    short events;  //注册的事件
    short revents; //实际发生的事件,由内核填充
}

nfds:数组的长度、元素的个数,用户关注的文件描述符的个数

timeout:超时时间

返回值:-1  出错

              0   超时

              >0 就绪文件描述符的个数

与select相比:

1.用户关注的事件类型更多

2.内核修改的和用户关注的事件分开表示,每次调用不需要重新设置

3.文件描述符不再是按位表示,直接用int类型

    3.1用户关注的文件描述符的值可以更大

    3.2用户关注的文件描述符的个数由用户数组决定,所以个数会更多。

poll返回时,也是将用户关注的所有文件描述符返回。

poll检测就绪文件描述符的时间复杂度O(n),poll返回后,用户程序依旧需要循环检测哪些文件描述符就绪。

 

#define _GNU_SOURCE
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<assert.h>
#include<sys/socket.h>
#include<sys/types.h>
#include<arpa/inet.h>
#include<netinet/in.h>
#include<poll.h>
 
#define SIZE 100//数组最大的长度

void init_fds(struct pollfd * fds)
{
	int i = 0;
	for(;i < SIZE;++i)
	{
		fds[i].fd = -1;
		fds[i].events = 0;
		fds[i].revents = 0;
	}
}

void inster_fds(struct pollfd * fds,int fd,short event)
{
	int i = 0;
	for(;i < SIZE ; ++i)
	{
		if(fds[i].fd = -1)
		{
			fds[i].fd = fd;//将文件描述符插入到数组里
			fds[i].events = event;//将事件插入到数组里
			break;
		}
	}
}

void delete_fd(struct pollfd * fds,int fd)
{
	int i = 0;
	for(; i < SIZE;++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 caddr,saddr;
	memset(&saddr,0,sizeof(saddr));
	saddr.sin_family = AF_INET;
	saddr.sin_port = htons(6000);
	saddr.sin_addr.s_addr = inet_addr("127.0.0.1");
	int res = bind(sockfd,(struct sockaddr *)&saddr,sizeof(saddr));
	assert(res != -1);
	listen(sockfd ,5);
	struct pollfd fds[SIZE];//定义数组
	init_fds(fds);//初始化数组
	inster_fds(fds,sockfd,POLLIN);//先将链接文件描述符插入数组里,只有读事件,所以选择POLLIN事件
	while(1)
	{
		int n = poll(fds,SIZE,-1);//
		if(n <= 0)
		{
			printf("poll error\n");
			continue;
		}
		//n>0,说明有文件描述符就绪,进行处理
		//将整个数组遍历一遍,检查哪个文件描述符就绪
		int i = 0;
		for(; i < SIZE ;++i)
		{
			if(fds[i].fd != -1)//fd != -1 才能进行判断l
			{
				int fd = fds[i].fd;	
				if(fds[i].revents & POLLRDHUP)//如果有关闭TCP链接的事件发生,进行断开链接处理
				{
					close(fd);
					delete_fd(fds,fd);
				}	
				else if(fds[i].revents & POLLIN)//检查是否有读事件就绪
				{
					if(fd == sockfd)//代表有客户端链接事件发生
					{
						int len = sizeof(caddr);
						int c = accept(fd,(struct sockaddr *) &caddr ,&len);
						if(c < 0)//出错处理
						{
							continue;
						}
						inster_fds(fds,c,POLLIN|POLLRDHUP);//将用户的链接套接字添加进数组里
					}
					else//代表客户端发送事件发生,进行接收数据处理
					{
						char buff [128] = {0};
						recv(fd,buff,127,0);
						printf("%d : %s",fd,buff);
						send(fd,"ok",2,0);
					}
				}
			}
		}
	}
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值