I/O复用之poll

函数功能:在一段在指定的时间内,监听用户感兴趣的可读、写、异常事件

函数原型:int poll(struct pollfd* fds,nfds_t* nfds,int timeout)   

fds:指向所有感兴趣的文件描述符上的可写、可读、异常事件,它是一个结构体的数组类型,每个格子都包含以下内容:

struct  pollfd

{

  int fd;//文件描述符

  short events;//注册的事件

  short revents//实际就绪的事件,由内核填充

};

poll支持的事件类型:

POLLIN

数据可读

POLLRDNORM

普通数据可读

POLLRDBAND

优先级带数据可读

(Linux下不支持)

POLLOUT

数据可写

POLLWRNORM

普通数据可读

POLLWRBAND

优先级带数据可写

nfds:表示sizeof(nfds)

timeout:表示poll的超时时间

poll所能监听的文件描述符个数为65535

函数功能实现过程

(1)应用程序通过poll函数的pollfd结构体将感兴趣的文件描述符和事件类型

(2)调用poll系统调用,将pollfd类型的结构体数组拷贝给内核空间,内核程序采用轮询方式查找所传入的数组中的就绪文件描述符,将内核处理之后的结果通过revents带回,这里的revents中不但有就绪的文件描述符,也有未就绪的,比select有优势的地方是内核并没有直接在传进的数组中修改状态,而是将传入的数组拷贝一份进行修改并由revents带回,所以下一次调用时不需要重新设置要监听的文件描述符;但是采用轮询方式时间复杂度为O(n)

(3)应用程序接受到内核返回的pollfd之后,同样采用轮询方式将events与revents遍历查找,时间复杂度为O(n),找出就绪的文件描述符

poll相对于select的优势

poll所能监听的文件描述符数达到系统允许打开的最大文件描述符数,而select由于_FD_SETSIZE的限制只能达到1023个

poll函数的缺点

(1)应用程序和内核程序都采用轮询方式查找就绪文件描述符,时间复杂度为O(n),

(2)poll仍需要每次调用将文件描述符数组拷贝一份给内核空间

(3)poll之工作在效率低下的LT模式下,在未处理就绪事件时会一直提醒就绪信息

简单poll使用

#define MAX 128
void Init(struct pollfd*fds,int len)
{
	int i = 0;
	for(; i < len ;++i)
	{
		fds[i].fd = -1;
		fds[i].events = 0;
	}
}

void Addfd(struct pollfd*fds,int len,int fd)
{
	int i = 0;
	for(; i < len ;++i)
	{
		if(fds[i].fd == -1)
		{
			fds[i].fd = fd;
			fds[i].events = POLLIN;
			break;
		}
	}
}

void main()
{
	int listen_fd = socket(AF_INET,SOCK_STREAM,0);//创建监听套接字
	assert(listen_fd != -1);
	struct sockaddr_in ser,cli;//在绑定函数中需要的结构体,用来记录客户端的iip地址和端口号
	ser.sin_family = AF_INET;//地址族:TCP/IP
	ser.sin_port = htons(6000);//将客户端端口号转化为网络字节序
	ser.sin_addr.s_addr = inet_addr("127.0.0.1");//将客户端的ip地址转化为网络字节序;注意这里输入的ip地址是链接本机;
	int ret = bind(listen_fd,(struct sockaddr*)&ser,sizeof(ser));//绑定监听套接字
	assert(ret != -1);
	listen(listen_fd,5);//监听
	printf("listen finish\n");

	struct pollfd fds[MAX];
	Init(fds,MAX);
	Addfd(fds,MAX,listen_fd);

	while(1)
	{
		int n = poll(fds,MAX,-1);
		assert(n != -1);
		if( n == 0)
		{
			printf("TIME OUT\n");
			continue;
		}

		int i = 0;
		for( ; i < MAX ;++i)
		{
			if(fds[i].fd == -1)
			{
				continue;
			}
			if(fds[i].revents & POLLIN)
			{
				int fd = fds[i].fd;

				if(fd == listen_fd)
				{
					int len = sizeof(cli);
					int c = accept(fd,(struct sockaddr*)&cli,&len);
					assert(c != -1);
					printf("CLI IS SUCCESS\n");

					Addfd(fds,MAX,c);
				}
				else
				{
					char buff[128] = {0};
					int n = recv(fd,buff,127,0);
					if(n <= 0)
					{
						printf("CLI IS FAILURE\n");
						close(fd);
						fds[i].fd = -1;
						fds[i].events = 0;
						continue;
				}
					printf("fd = %d   buff::   %s\n",fd,buff);
					send(fd,"OK",2,0);

				}
			}
		}
	

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值