Linux编程基础 8.4:epoll工作模式

1 简介

poll机制的工作原理及流程与select类似,但poll可监控的进程数量不受select中第二个因素——fd_set集合容量的限制,用户可在程序中自行设置被监测的文件描述符集的容量,当然poll在阻塞模式下也采用轮询的方式监测文件描述符集,因此应合理设置poll中监控进程的数量。

2 poll函数

poll()函数存在于函数库poll.h中,其声明如下:

int poll(struct pollfd *fds, nfds_t nfds, int timeout);
  • 参数fds是一个struct pollfd类型的指针,主要用于传入被监测的多个文件描述符,其数据类型struct pollfd的定义如下:
struct pollfd{
	int fd;				//文件描述符,设置为-1时,表示取消对该文件描述符的监测
	short events;		//等待的事件
	short revents;		//实际发生的事件
}
                                         poll事件相关宏及其说明

在这里插入图片描述

  • 参数nfds等同于select()函数中的参数nfds,用来设置pollt监控的文件描述符的范围,需设置为文件描述符最大值加1;

  • 参数timeout与select()函数中的参数timeout,都用于设置组设时长,但其取值略有差异,poll()函数中参数timeout的取值及其对应含义如下:
    – 当timeout=-1时,poll()函数阻塞等待;
    – 当timeout=0时,poll()函数将立即返回,以轮询的方式监测文件描述符表;
    – 当timeout>0时,等待指定时长(单位为毫秒,若当前系统时间精度不够毫秒则向上取值)。

  • poll()函数若调用成功将返回就绪文件描述符数量;若等待超时,将返回0,表示没有已就绪的文件描述符;若调用出错,将返回-1,并设置errno。

【案例】:使用poll模型搭建多路I/O转接服务器,使服务器可接收客户端数据,并将接收到的数据转为大写,写回客户端;使客户端可向服务器发送数据,并将服务器返回的数据打印到终端。

poll_s.c					//服务器
 1#include <stdio.h>
 2#include <stdlib.h>
 3#include <string.h>
 4#include <netinet/in.h>
 5#include <arpa/inet.h>
 6#include <poll.h>
 7#include <errno.h>
 8#include "wrap.h"
 9#define MAXLINE 80						//缓冲数组大小
 10#define SERV_PORT 8000					//端口号
 11#define OPEN_MAX 1024					//最大打开文件描述符数量
 12int main()
 13{
 14	int i, j, maxi, listenfd, connfd, sockfd;
 15	int nready;
 16	ssize_t n;
 17	char buf[MAXLINE], str[INET_ADDRSTRLEN];
 18	socklen_t clilen;
 19	struct pollfd client[OPEN_MAX];		//文件描述符与事件集合
 20	struct sockaddr_in cliaddr, servaddr;
 21	listenfd = Socket(AF_INET, SOCK_STREAM, 0);
 22	bzero(&servaddr, sizeof(servaddr));
 23	servaddr.sin_family = AF_INET;
 24	servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
 25	servaddr.sin_port = htons(SERV_PORT);
 26	Bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr));
 27	Listen(listenfd, 20);
 28 	//初始化poll()的参数fds
 29	client[0].fd = listenfd;
 30	client[0].events = POLLRDNORM;	//设置listenfd监听普通读事件
 31	for (i = 1; i < OPEN_MAX; i++)
 32		client[i].fd = -1; 		//将client[]中其余元素的fd成员初始化为-1
 33	maxi = 0; 					//记录client[]数组有效元素中最大元素下标
 34	//使用poll()机制循环检测文件描述符集合
 35 	for (;;) {
 36		nready = poll(client, maxi + 1, -1);	//阻塞等待请求到达
 37 		//通过listenfd状态判断是否有客户端连接请求,如有则建立连接
 38		if (client[0].revents & POLLRDNORM) {
 39			clilen = sizeof(cliaddr);
 40			connfd = Accept(listenfd,(struct sockaddr *)&cliaddr,&clilen);
 41			printf("received from %s at PORT %d\n",
 42				inet_ntop(AF_INET, &cliaddr.sin_addr, str, sizeof(str)),
 43				ntohs(cliaddr.sin_port));
 44 			//将accept返回的connfd存放到client[]中的空闲位置
 45			for (i = 1; i < OPEN_MAX; i++){
 46				if (client[i].fd < 0) {
 47					client[i].fd = connfd;
 48					break;
 49				}
 50 			}
 51			if (i == OPEN_MAX)
 52				perr_exit("too many clients");
 53			client[i].events = POLLRDNORM; 	//设置刚刚返回的connfd,监控读事件
 54			if (i > maxi)					//更新client[]中最大元素下标
 55				maxi = i;
 56			if (--nready <= 0) 				//若无就绪事件,回到poll阻塞
 57				continue;
 58		}
 59 		//检测client[],处理有就绪事件的文件描述符
 60		for (i = 1; i <= maxi; i++){
 61			if ((sockfd = client[i].fd) < 0)
 62				continue;
 63			if (client[i].revents & (POLLRDNORM | POLLERR)) {
 64				if ((n = Read(sockfd, buf, MAXLINE)) < 0) {
 65 					//比较errno,若为RST则表示连接中断
 66					if (errno == ECONNRESET){
 67						printf("client[%d] aborted connection\n", i);
 68						Close(sockfd);
 69						client[i].fd = -1;
 70					}
 71					else
 72						perr_exit("read error");
 73				}
 74				else if (n == 0) {//连接由客户端关闭
 75					printf("client[%d] closed connection\n", i);
 76					Close(sockfd);
 77					client[i].fd = -1;
 78				}
 79				else {//若成功读取数据,则对数据进行操作
 80					for (j = 0; j < n; j++)
 81						buf[j] = toupper(buf[j]);
 82					Writen(sockfd, buf, n);
 83				}
 84 				//当就绪文件描述符数量为0时,终止循环
 85				if (--nready <= 0)
 86					break; 
 87			}
 88		}
 89	}
 90	return 0;
 }
poll_c.c					//客户端
 1#include <stdio.h>
 2#include <string.h>
 3#include <unistd.h>
 4#include <netinet/in.h>
 5#include "wrap.h"
 6#define MAXLINE 80						//缓冲数组大小
 7#define SERV_PORT 8000					//端口号
 8int main()
 9{
 10	struct sockaddr_in servaddr;
 11	char buf[MAXLINE];
 12	int sockfd, n;
 13	sockfd = Socket(AF_INET, SOCK_STREAM, 0);
 14	bzero(&servaddr, sizeof(servaddr));
 15	servaddr.sin_family = AF_INET;
 16	inet_pton(AF_INET, "127.0.0.1", &servaddr.sin_addr);
 17	servaddr.sin_port = htons(SERV_PORT);
 18	Connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr));
 19	while (fgets(buf, MAXLINE, stdin) != NULL) {
 20		Write(sockfd, buf, strlen(buf));
 21		n = Read(sockfd, buf, MAXLINE);
 22		if (n == 0)
 23			printf("the other side has been closed.\n");
 24		else
 25			Write(STDOUT_FILENO, buf, n);
 26	}
 27	Close(sockfd);
 28	return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/665780.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【React】封装一个好用方便的消息框(Hooks Bootstrap 实践)

引言 以 Bootstrap 为例&#xff0c;使用模态框编写一个简单的消息框&#xff1a; import { useState } from "react"; import { Modal } from "react-bootstrap"; import Button from "react-bootstrap/Button"; import bootstrap/dist/css/b…

【LeetCode】38.外观数列

外观数列 题目描述&#xff1a; 「外观数列」是一个数位字符串序列&#xff0c;由递归公式定义&#xff1a; countAndSay(1) "1"countAndSay(n) 是 countAndSay(n-1) 的行程长度编码。 行程长度编码&#xff08;RLE&#xff09;是一种字符串压缩方法&#xff0c…

STL中list的模拟实现

目录 list模拟实现 list节点 list的push_back()函数 list的迭代器操作&#xff08;非const&#xff09; list的迭代器操作&#xff08;const&#xff09; list迭代器const 非const优化 list的insert()函数 list的erase()函数 list的pop_back() push_front() pop_front(…

数据结构:希尔排序

文章目录 前言一、排序的概念及其运用二、常见排序算法的实现 1.插入排序2.希尔排序总结 前言 排序在生活中有许多实际的运用。以下是一些例子&#xff1a; 购物清单&#xff1a;当我们去超市购物时&#xff0c;通常会列出一份购物清单。将购物清单按照需要购买的顺序排序&…

【STM32F103】HC-SR04超声波测距

【STM32F103】HC-SR04超声波测距 一、HC-SR041、工作原理2、其他参数及时序图 二、代码编写思路三、HAL配置四、代码实现五、实验结果 前言 本次实验主要实现用stm32f103HC-SR04实现超声波测距&#xff0c;将测距数值通过串口上传到上位机串口助手 一、HC-SR04 1、工作原理 (…

String类型的二维数组怎么写

今天做题遇到一个问题&#xff1a;就是需要写String类型的二维数组时&#xff0c;我蒙圈了。后来查了资料发现&#xff0c;String类型的二维数组其实是由若干个一维数组构成的。 1.先初始化一个二维数组&#xff1a;List<List<String>> list new ArrayList<&g…

登录校验及全局异常处理器

登录校验 会话技术 会话:用户打开浏览器,访问web服务器的资源,会话建立,直到有一方断开连接,会话结束.在一次会话中可以包含多次请求和响应会话跟踪:一种维护浏览器状态的方法,服务器需要识别多次请求是否来自于同一浏览器,以便在同一次会话请求间共享数据会话跟踪方案 客户端…

MT8781安卓核心板_MTK联发科Helio G99核心板规格参数

MT8781安卓核心板采用先进的台积电6纳米级芯片生产工艺&#xff0c;配备高性能Arm Cortex-A76处理器和Arm Mali G57 GPU&#xff0c;加上LPDDR4X内存和UFS 2.2存储&#xff0c;在处理速度和数据访问速度上都有着出色的表现。 MT8781还支持120Hz显示器&#xff0c;无需额外的DSC…

Transformer模型学习(1)

Transformer模型&#xff0c;它自2017年被引入以来&#xff0c;已成为处理语言任务的主流技术。Transformer模型不仅在多个语言处理任务上取得了优异的成绩&#xff0c;而且还因为它的设计极大地推动了后续模型的发展&#xff0c;如今广泛应用于聊天机器人、翻译软件和文本生成…

CS的下载+内网穿透

CS的下载 纵向渗透&#xff1a;NC 瑞士军刀菜刀是一个hyyp协议 NC是TCP NC连接后没有任何回显 先受控房 nc.exe -l -p 12345 然后攻击方 nc.exe ip port 12345 扫描端口 上传和 nc.exe 同一目录下的文件 跳板机工具和NC的实际操作以及Termite联合管理 和nc是一样的…

2024年生成式AI使用趋势报告

生成式AI技术及产品发展概况 人工智能技术奇点降临&#xff0c;搜索成为大模型技术落地的“首站” 过去几十年&#xff0c;人工智能长期鲜有突破性的发展&#xff0c;直至2022年AI大模型技术奇点的出现&#xff0c;使得AI能力发生了颠覆性的变化&#xff0c;人工智能受到了前…

cdo | 常用命令

整理一下平时经常会使用的cdo命令 如何来更改netcdf数据中的变量名呢&#xff1f; 假设我现在有一个sst月平均数据,希望将里面的变量名称sst修改为sst_new netcdf oisst_monthly { dimensions:lat 180 ;lon 360 ;time UNLIMITED ; // (476 currently)nbnds 2 ; variable…

利用“记忆化搜索“解斐波那契数

一、题目描述 求第 n 个斐波那契数。 二、 利用"记忆化搜索"解斐波那契数 什么是记忆化搜索&#xff1f;记忆化搜索就是带有备忘录的递归。 我们先来看一下使用递归来解斐波那契数的这个过程&#xff0c;假设求第5个斐波那契数F(5)。 由图可见&#xff0c;要重复计…

【mysql数据库】mycat中间件

MyCat 简介 Mycat 是数据库 中间件 。 1、 数据库中间件 中间件 是一类连接软件组件和应用的计算机软件&#xff0c; 以便于软件各部件之间的沟通 。 例子 Tomcat web 中间件 。 数据库 中间件 连接 java 应用程序和数据库 2、 为什么要用 Mycat ① Java 与数据库紧耦合 …

Halcon 光度立体 缺陷检测

一、概述 halcon——缺陷检测常用方法总结&#xff08;光度立体&#xff09; - 唯有自己强大 - 博客园 (cnblogs.com) 上周去了康耐视的新品发布会&#xff0c;我真的感觉压力山大&#xff0c;因为VM可以实现现在项目中的80% 的功能&#xff0c;感觉自己的不久就要失业了。同时…

基于Python的校园预约打印网站的实现

基于Python的校园预约打印网站的实现 开发语言:Python 数据库&#xff1a;MySQL所用到的知识&#xff1a;Django框架工具&#xff1a;pycharm、Navicat、Maven 系统功能实现 注册 新用户首先要进行注册信息填写&#xff0c;填写完成以后进行登录即可使用此网站 打印社 分别有…

vue3 前端实现导出下载pdf文件

这样的数据实现导出 yourArrayBufferOrByteArray 就是后端返回数据 // 创建Blob对象const blob new Blob([new Uint8Array(res)], { type: application/pdf })// 创建一个表示该Blob的URLconst url URL.createObjectURL(blob);// 创建一个a标签用于下载const a document.cr…

使用Redis缓存实现短信登录逻辑,手机验证码缓存,用户信息缓存

引入依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency> 加配置 spring:redis:host: 127.0.0.1 #redis地址port: 6379 #端口password: 123456 #密码…

三十二篇:转化决策为行动:探索决策支持系统的深层价值

转化决策为行动&#xff1a;探索决策支持系统的深层价值 1. DSS的精髓&#xff1a;定义与核心功能 1.1 定义与作用 在现代商业的快速演变中&#xff0c;决策支持系统&#xff08;Decision Support Systems, DSS&#xff09;已成为企业获得竞争优势的重要工具。DSS是一种利用先…

全国产飞腾模块麒麟信安操作系统安全漏洞

1、背景介绍 目前在全国产飞腾模块上部署了麒麟信安操作系统&#xff0c;经第三方机构检测存在以下漏洞 操作系统版本为 内核版本为 openssh版本为 2、openssh CBC模式漏洞解决 首先查看ssh加密信息 nmap --script "ssh2*" 127.0.0.1 | grep -i cbc 可以通过修改/…