I/O模型之poll模型

1.poll与select,epoll比较

poll主要是解决select的最大文件描述符限制提出的,与select一样都是轮询文件描述符,所以效率方便也无法与epoll相比,另外poll不具备移植性,只有在linux系统上有实现,在windows系统没有poll模型的实现
2.poll模型效率

poll本质上和select没有区别,它将用户传入的数组拷贝到内核空间,然后查询每个fd对应的设备状态,如果设备就绪则在设备等待队列中加入一项并继续遍历,如果遍历完所有fd后没有发现就绪设备,则挂起当前进程,直到设备就绪或者主动超时,被唤醒后它又要再次遍历fd。这个过程经历了多次无谓的遍历。

它没有最大连接数的限制,原因是它是基于链表来存储的,但是同样有如下缺点:
1.大量的fd的数组被整体复制于用户态和内核地址空间之间,而不管这样的复制是不是有意义。   
2.poll还有一个特点是“水平触发”,如果报告了fd后,没有被处理,那么下次poll时会再次报告该fd。

 

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

    参数:

    第一个参数是指向一个结构数组的第一个元素的指针,每个元素都是一个pollfd结构,用于指定测试某个给定描述符的条件。

    第二个参数是要监听的文件描述符的个数,也就是数组fds的元素个数。

    第三个参数意义与select相同。

    函数的返回值

    成功返回的是有事件的描述符号的个数,出错返回-1,如果返回0,代表等待时间结束,但是没有事件发生。

编码流程

        定义pollfd结构体数组

        初始化pollfd结构体数组

        设置监听poll事件

        等待poll事件

        判断触发事件的描述符,并做对应处理。
 

代码如下:
 

#include <stdio.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <ctype.h>
#include <sys/select.h>
#include <sys/poll.h>
#include <string.h>

#define	SERVERIP "192.168.11.128" 
#define	SERVERPORT	8000
#define	BUFSIZE	1500
#define	IPSIZE	16
#define	LISTEN	128


int main(void)
{
		struct sockaddr_in serveraddr,clientaddr;
		int ready=0;
		struct pollfd clientarr[4096];
		char buf[BUFSIZE];
		int len;
		int clientfd;
		bzero(&serveraddr,sizeof(serveraddr));
		serveraddr.sin_family = AF_INET;
		serveraddr.sin_port = htons(SERVERPORT);
		inet_pton(AF_INET,SERVERIP,&serveraddr.sin_addr.s_addr);
		int serverfd = socket(AF_INET,SOCK_STREAM,0);
		bind(serverfd,(struct sockaddr*)&serveraddr,sizeof(serveraddr));
		listen(serverfd,LISTEN);
		for(int i=0;i<4096;i++)
				clientarr[i].fd=-1;
		clientarr[0].fd=serverfd;
		clientarr[0].events = POLLIN;
		printf("Poll Server Runing....\n");
		while(1)
		{
				ready = poll(clientarr,4096,-1);
				if(ready == -1)
						perror("Poll Call Failed..\n");
				else{
						while(ready--){
								if(clientarr[0].revents & POLLIN)	
								{
										int clientsize = sizeof(clientaddr);
										//建立新的链接
										clientfd = accept(serverfd,(struct sockaddr*)&clientaddr,&clientsize);
										//将新的描述符加入到socket数组中
										for(int i=1;i<4096;i++)
										{
												if(clientarr[i].fd==-1)
												{
														clientarr[i].fd=clientfd;
														clientarr[i].events=POLLIN;
														break;
												}
										}
								}else{
										for(int i=1;i<4096;i++){
												if(clientarr[i].fd!=-1)
												{
														if(clientarr[i].revents & POLLIN)
														{
																if((len = read(clientarr[i].fd,buf,sizeof(buf)))>0)
																{
																		int j=0;
																		while(len > j)
																		{
																				buf[j]=toupper(buf[j]);
																				j++;
																		}
																		write(clientarr[i].fd,buf,len);
																		bzero(buf,sizeof(buf));
																}else if(len == 0){
																		//要关闭文件描述符
																		close(clientarr[i].fd);
																		//将该socket从监听集合摘除
																		clientarr[i].fd=-1;
																}
																break;
														}
												}
										}
								}

						}
				}
		}
}

 

部分摘抄自:
原文:https://blog.csdn.net/qq_40477151/article/details/80355797

原文:https://blog.csdn.net/shixin_0125/article/details/72604343

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值