Linux学习笔记(epoll,IO多路复用)

Linux learning note

  • 1、epoll的使用场景
  • 2、epoll的使用方法和内部原理
    • 2.1、创建epoll
    • 2.2、使用epoll监听和处理事件
  • 3、示例

1、epoll的使用场景

epoll的英文全称是extend poll,顾名思义是poll的升级版。常见的IO复用技术有select,poll,epoll三种,本文只介绍epoll。
这里IO多路复用通俗理解是指用一个线程来管理多个输入/输出通道。具体到网络场景中,就是希望服务器只用一个线程就可以处理N个客户端的读写请求。
如果不适用IO多路复用技术,我们当然也可以实现一个服务端和N个客户端之间建立连接,但由于read函数经常被设置为阻塞式的,所以出现这么一种情况:服务器阻塞在客户端1的通道上,而当客户端2发送消息时便无法及时处理。
当然read函数也可以设置为非阻塞式的,不断的扫描哪个客户端发送消息,不过这样就很浪费CPU资源了。
总而言之,epoll在网络通信中几乎是必不可少的一项技术。

2、epoll的使用方法和内部原理

先概况性的讲,epoll是一个管理服务端和多个客户端的工具,当这些设备有“动作”的时候,epoll会通过中断察觉到这些“动作”,并及时去处理。
具体原理如下:

2.1、创建epoll

使用epoll_create()函数创建一个eventpoll的结构体,该结构体又嵌套着许多数据结构,用以维护epoll管理的多个服务器和客户端。其中较为重要的是一个存放服务器和所有客户端的文件描述符的红黑树和一个管理就绪事件的双向链表ready list
在这里插入图片描述
值得注意的是,epoll_create()只是创建eventpoll这么一个数据结构,具体红黑树中的节点的添加和删除需要依靠epoll_ctl()函数来完成。而epoll_ctl()不仅仅添加需要监控的文件描述符,还要添加一个名为epoll_event的结构体,我们可以通过该结构体设置我们需要监听的事件和触发中断的方式。
在这里插入图片描述
监听的事件和触发中断的方式都是通过设置epoll_event中的events这个成员变量来完成的,常规的设置有

struct event_poll ev;
ev.events = EPOLLIN;	//设置监听读事件,如果没有设置触发方式则默认使用水平触发
//or
ev.events = EPOLLIN | EPOLLET;	//设置监听读事件,且边缘触发
  • 水平触发(level triggered):当事件发生之后,一直产生中断,提醒CPU去处理。这也是默认的触发方式。
  • 边缘触发(edge triggered):当事件发生之后,只触发一次中断。

2.2、使用epoll监听和处理事件

这部分就相对简单许多了,无非是在while循环中使用一个epoll_wait()去监听哪一个设备有需要处理的事件。其中epoll_wait()时常被设置成阻塞性函数,即没有事件需要处理的时候就一直阻塞在那。如果有事件需要处理,CPU会把该事件对应的文件描述符放进ready_list,然后通过epoll_wait()函数再将ready_list中的文件描述符对应的设备的事件信息等依次放入epoll_event的队列中来。最后在通过对epoll_event中的文件描述符或事件类型的判断,去决定执行具体的任务。
在这里插入图片描述
可能有点难理解,那再看看代码把。

struct epoll_event events[1024];
int epollfd = epoll_create(1);
/***
A lot of code is omitted here
***/
while(true)
{
	int nfds = epoll_wait(epollfd, events, 1024, -1);
	for (int n = 0; n < nfds; ++n) {
		if (events[n].events & EPOLLIN)		//去处理一个个事件
		{
			/******/
		}
	}
}

3、示例

该例子完成了一个服务器对多个客户端的连接请求的监控以及对可读事件的回应。

#include <sys/epoll.h>
#include <netinet/in.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <fcntl.h>
#include <iostream>

#define MAX_EVENTS 10
#define READ_SIZE 1024

int server_port = 8888;


int main() {
    struct epoll_event ev, events[MAX_EVENTS];
    struct sockaddr_in addr;
    char buffer[READ_SIZE];


    int listen_sock = socket(AF_INET, SOCK_STREAM, 0);
    memset(&addr, 0, sizeof(addr));
    addr.sin_family = AF_INET;
    addr.sin_addr.s_addr = INADDR_ANY;
    addr.sin_port = htons(server_port);

    bind(listen_sock, (struct sockaddr*) &addr, sizeof(addr));
    listen(listen_sock, 5);


    int epollfd = epoll_create(1);
    ev.events = EPOLLIN;    
    ev.data.fd = listen_sock;
    epoll_ctl(epollfd, EPOLL_CTL_ADD, listen_sock, &ev);
    
    int nfds;  
    while(true) 
    {
        nfds = epoll_wait(epollfd, events, MAX_EVENTS, -1);
        for (int n = 0; n < nfds; ++n) {
            if (events[n].data.fd == listen_sock) {
                int con_sock = accept(listen_sock, (struct sockaddr *) NULL, NULL);
                ev.events = EPOLLIN | EPOLLET;
                ev.data.fd = con_sock;
                epoll_ctl(epollfd, EPOLL_CTL_ADD, con_sock, &ev);
                std::cout << "add a new client suessfully!" << std::endl;
            } 
            else {
                if (events[n].events & EPOLLIN) {
                    int len  = read(events[n].data.fd, buffer, sizeof(buffer));
                    if(len > 0){
                        std::cout << "server receive is: " << buffer << std::endl;
                        static std::string send_str;
                        send_str.append("receive suessfully!");
                        write(events[n].data.fd, send_str.c_str(), send_str.length());
                        memset(buffer, 0 , sizeof(buffer));
                        send_str.erase(0);
                    } 
                }
            }
        }
    }
    close(listen_sock);
    return 0;
}

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

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

相关文章

HaloDB 的 Oracle 兼容模式

↑ 关注“少安事务所”公众号&#xff0c;欢迎⭐收藏&#xff0c;不错过精彩内容~ 前倾回顾 前面介绍了“光环”数据库的基本情况和安装办法。 哈喽&#xff0c;国产数据库&#xff01;Halo DB! 三步走&#xff0c;Halo DB 安装指引 ★ HaloDB是基于原生PG打造的新一代高性能安…

海医大三院使用先进血管外科微创技术成功救治危重主动脉夹层患者

近日,上海东方肝胆外科医院血管外科周建教授团队采用主动脉弓分支型一体化移植物联合体外开窗技术,成功救治复杂危重主动脉夹层患者,为上海嘉定首例,彰显了上海东方肝胆外科医院血管外科的优势与特色。 患者谢先生,72岁,两周前突发剧烈胸背部撕裂样疼痛,休息后症状未能得到缓解…

MyBatis的坑(动态SQL会把0和空串比较相等为true)

文章目录 前言一、场景如下二、原因分析1. 源码分析2. 写代码验证 三、解决办法代码及执行结果如下 总结 前言 在开发过程中遇到MyBatis的动态SQL的if条件不生效的情况&#xff0c;但经过debuger发现并不是参数问题&#xff0c;已经拿到了参数并传给了MyBatis&#xff0c;且从表…

APP逆向之调试的开启

很基础的一个功能设置&#xff0c;大佬轻喷。 背景 在开始进行对APP逆向分析的时候&#xff0c;需要对APP打开调试模式。 打开调试的模式有多种方式可以通过直接改包方式也可以通过借助第三方工具进行打开调试模式。 下面就整理下这个打开调试模式的一些方式。 改包修改模…

计算机网络学习笔记——应用层

一、应用层概述 二、客户/服务器方式(C/S方式)和对等方式(P2P方式) 客户/服务器(Client/Server&#xff0c;C/S)方式 服务器总是处于运行状态&#xff0c;并等待客户的服务请求。服务器具有固定端口号(例如HTTP服务器的默认端口号为80)&#xff0c;而运行服务器的主机也具有固…

四川汇聚荣聚荣科技有限公司是正规的吗?

在当今社会&#xff0c;随着科技的飞速发展&#xff0c;越来越多的科技公司如雨后春笋般涌现。然而&#xff0c;在这个信息爆炸的时代&#xff0c;如何判断一家公司是否正规成为了许多人关注的焦点。本文将围绕“四川汇聚荣聚荣科技有限公司是否正规”这一问题展开讨论&#xf…

社区供稿丨GPT-4o 对实时互动与 RTC 的影响

以下文章来源于共识粉碎机 &#xff0c;作者AI芋圆子 前面的话&#xff1a; GPT-4o 发布当周&#xff0c;我们的社区伙伴「共识粉碎机」就主办了一场主题为「GPT-4o 对实时互动与 RTC 的影响」讨论会。涉及的话题包括&#xff1a; GPT-4o 如何降低延迟&#xff08;VAD 模块可…

从一维到二维:数组转换的奥秘与应用

新书上架~&#x1f447;全国包邮奥~ python实用小工具开发教程http://pythontoolsteach.com/3 欢迎关注我&#x1f446;&#xff0c;收藏下次不迷路┗|&#xff40;O′|┛ 嗷~~ 目录 一、引言&#xff1a;数组转换的魅力 二、一维数组转二维数组的基础方法 1. 确定二维数组的…

爬虫案例(读书网)

一.我们还是使用简单的bs4库和lxml&#xff0c;使用xpath&#xff1a; 导入下面的库&#xff1a; import requests from bs4 import BeautifulSoup from lxml import etree 我们可以看见它的div和每个书的div框架&#xff0c;这样会观察会快速提高我们的简单爬取能力。 二.实…

蓝桥杯算法心得——李白打酒(加强版)

大家好&#xff0c;我是晴天学长&#xff0c;记忆化搜索&#xff0c;找到技巧非常重要&#xff0c;需要的小伙伴可以关注支持一下哦&#xff01;后续会继续更新的。&#x1f4aa;&#x1f4aa;&#x1f4aa; 2) .算法思路 1.memo三维表示记录的结果 3&#xff09;.算法步骤 1…

1、C++编程概述

文章目录 一、基本概念二、数据的表示及运算计算机中数据表示进制间相互转化二进制计算规则 三、计算机数据的存储单位四、机器数和码制五、机器数运算机器数的加减运算机器数的乘除运算 面向对象编程语言把事物看成是具有属性和行为的对象&#xff0c;然后通过抽象找出属于同一…

命令行解析器浅解

1、什么叫解析器&#xff1f; 解析器&#xff08;parser&#xff09;是一种程序或组件&#xff0c;用于分析输入的数据&#xff0c;并将其转换为更易于处理的格式。解析器在计算机科学中有广泛的应用&#xff0c;特别是在编译器、解释器、自然语言处理和数据格式转换等领域。 1…

计算机网络学习笔记——运输层(b站)

目录 一、 运输层概述 二、运输层端口号、复用与分用的概念 三、UDP和TCP的对比 四、TCP的流量控制 五、TCP的拥塞控制 六、TCP超时重传时间的选择 七、TCP可靠传输的实现 八、TCP报文段的首部格式 一、 运输层概述 物理层、数据链路层、网络层实现了主机到主机的通信…

存储器和CPU的连接与TCP的流量控制

存储器与CPU的连接 存储容量的拓展 &#xff08;1)位拓展&#xff1a;增加存储字长 &#xff08;2&#xff09;字拓展 增加存储器字的数量 例题&#xff1a;设CPU有16根地址线&#xff0c;8根数据线&#xff0c;并用MREQ作为访问存储控制信号(低电平有效)&#xff0c;WR作为…

错误记录:从把项目从Tomcat8.5.37转到Tomcat10.1.7

错误信息&#xff1a;在本地Servlet项目里没有报错&#xff0c;但是浏览器跳转该servlet时报错 型 异常报告 消息 实例化Servlet类[com.wangdao.lx.MyServlet1]异常 描述 服务器遇到一个意外的情况&#xff0c;阻止它完成请求。 例外情况 jakarta.servlet.ServletExceptio…

debian11安装留档@VirtualBox

因为debian12无法安装tpot&#xff0c;所以又把11重新安装一遍&#xff0c;以前的安装文档&#xff1a;安装Debian 11 留档-CSDN博客 下载光盘 华为云地址&#xff1a;https://repo.huaweicloud.com/debian-cd/11.0.0/amd64/iso-cd/ 使用了debian11 教育版&#xff0c;比较有…

Spring Cache自定义缓存key和过期时间

一、自定义全局缓存key和双冒号替换 使用 Redis的客户端 Spring Cache时&#xff0c;会发现生成 key中会多出一个冒号&#xff0c;而且有一个空节点的存在。 查看源码可知&#xff0c;这是因为 Spring Cache默认生成key的策略就是通过两个冒号来拼接。 同时 Spring Cache缓存…

【开源三方库】Aki:一行代码极简体验JSC++跨语言交互

一、简介 OpenAtom OpenHarmony&#xff08;以下简称“OpenHarmony”&#xff09;的前端开发语言是ArkTS&#xff0c;在TypeScript&#xff08;简称TS&#xff09;生态基础上做了进一步扩展&#xff0c;继承了TS的所有特性&#xff0c;是JavaScript&#xff08;简称JS&#xf…

大模型时代的具身智能系列专题(五)

stanford宋舒然团队 宋舒然是斯坦福大学的助理教授。在此之前&#xff0c;他曾是哥伦比亚大学的助理教授&#xff0c;是Columbia Artificial Intelligence and Robotics Lab的负责人。他的研究聚焦于计算机视觉和机器人技术。本科毕业于香港科技大学。 主题相关作品 diffusio…

MySQL之创建高性能的索引(六)

创建高性能的索引 选择合适的索引列顺序 当使用前缀索引的时候&#xff0c;在某些条件值的基数比正常值高的时候&#xff0c;问题就来了。例如&#xff0c;在某些应用程序中&#xff0c;对于没有登录的用户&#xff0c;都将其用户名记录为"guest"&#xff0c;在记录…