多路复用之POLL模型

多路复用之POLL

poll机制的引入:
主要解决select中的文件描述符集上限FD_SETSIZE(1024);原理跟select类似,也是采用轮询形式。

API:

int poll(struct pollfd *fds, nfds_t nfds, int timeout);
\
参数1	struct pollfd {
			int fd; /* 文件描述符*/
			short events; /* 监控的事件*/
			short revents; /* 监控事件中满足条件返回的事件*/
			};
参数2 监控文件描述符的数量
参数3 0为非阻塞,-1为阻塞,>0为阻塞时间(毫秒级等待)
/

该API用法相对比select要简单,

  1. 每次select调用要对描述符集进行备份,已恢复描述符集的状态,而poll的events为要监控的对象,revents为保存事件发生后的文件描述符集。
  2. 参数1为结构体数组,每个文件描述符对应一个。监控时数组时判断fd的值域,一般用-1表示空,>=0则为有对象。
  3. 事件的状态(带外优先一般表示socket的读写)
		POLLIN普通或带外优先数据可读,即POLLRDNORM | POLLRDBAND
		POLLRDNORM-数据可读
		POLLRDBAND-优先级带数据可读
		POLLPRI 高优先级可读数据
		
		POLLOUT普通或带外数据可写
		POLLWRNORM-数据可写
		POLLWRBAND-优先级带数据可写
		
		POLLERR 发生错误
		POLLHUP 发生挂起
		POLLNVAL 描述字不是一个打开的文件

扩展:ppoll GNU定义了ppoll(非POSIX标准),可以支持设置信号屏蔽字

附上代码:

#include <stdio.h>
#include <stdlib.h>
#include <poll.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "wrap.h"
#include <errno.h>
#include <string.h>

#define SERV_PORT 8000
#define MAX_LINE 128
#define OPEN_MAX 1024

int main(int argc, char *argv[])
{
	int serv_fd, connfd, i, j, maxi, sockfd, nready;
	ssize_t n;
	char buf[MAX_LINE], str[INET_ADDRSTRLEN];
	struct sockaddr_in servaddr,clientaddr;
	socklen_t clilen;
	struct pollfd client[OPEN_MAX];

	serv_fd = Socket(AF_INET, SOCK_STREAM, 0);
	servaddr.sin_family = AF_INET;
	servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
	servaddr.sin_port = htons(SERV_PORT);
	Bind(serv_fd, (struct sockaddr *)&servaddr, sizeof(servaddr));
	Listen(serv_fd, 20);

	client[0].fd = serv_fd;
	client[0].events = POLLRDNORM;

	for(i = 1; i < OPEN_MAX; i++)
		client[i].fd = -1;
	maxi = 0;
	
	for( ; ; ){
		nready = poll(client, maxi + 1, -1);
		if(client[0].revents & POLLRDNORM){
			clilen = sizeof(clientaddr);
			connfd = Accept(serv_fd, (struct sockaddr *)&clientaddr, &clilen );

			for(i = 1; i < OPEN_MAX; i++)
				if(client[i].fd < 0){
					client[i].fd = connfd;
					break;
				}
				if(i == OPEN_MAX)
					perr_exit("too many client");
				client[i].events = POLLRDNORM;
				if(i > maxi) maxi = i;
				if(--nready <= 0) continue;
		}
		for(i = 1; i <= maxi; i++){
			if((sockfd = client[i].fd) < 0)
				continue;
			else if(client[i].revents & (POLLRDNORM | POLLERR))
			{
				if((n = Read(sockfd, buf, MAX_LINE)) < 0)
				{
					if(errno == ECONNRESET){
						printf("cli[%d] abort\n",i);
						Close(sockfd);
						client[i].fd = -1;
					}else
						perr_exit("read error");
				}
				else if(n == 0){
					printf("cli[%d] closed\n",i);
					Close(sockfd);
					client[i].fd = -1;
				}else{
					for(j = 0; j < n; j++){
						buf[j] = toupper(buf[j]);
					}
					Writen(sockfd, buf, n);
				}
				if(--nready <= 0)
					break;
			}

		}
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值