linux关于epoll概述(各项组成,以及作用)

在 Linux 中,多个进程可以各自创建自己的 epoll 对象,每个进程都有独立的 epoll 实例,即拥有独立的 eventpoll 结构体和相关的数据结构(如红黑树、就绪列表等)。

当一个进程调用 epoll_create 函数时,Linux 内核会为该进程创建一个 eventpoll 对象。这个对象用于管理该进程所关注的文件描述符及其相关事件。

每个进程通过 epoll_ctl 函数向自己的 epoll 对象中添加、修改或删除需要监听的文件描述符及其事件。

通过 epoll_wait 函数,进程可以阻塞等待其 epoll 对象中注册的事件发生,并获取发生的事件。

这样,不同的进程可以独立地管理自己的文件描述符集合,各自进行事件的监听和处理,它们之间不会相互干扰。

多个进程可以有多个 epoll 对象, epoll 也可以在一个进程内实现高效的 I/O 多路复用,集中管理和处理多个文件描述符的事件。而这里进一步说明了多个进程可以各自使用 epoll 来管理属于自己进程的文件描述符,每个进程都有自己独立的管理机制。

例如,进程 A 和进程 B 都可以创建自己的 epoll 对象,分别添加各自需要监听的文件描述符,并通过各自的 epoll_wait 等待事件发生,然后进行相应的处理。它们的 epoll 操作是相互独立的。

epoll 的这种设计使得在多进程环境中,每个进程都可以根据自己的需求灵活地使用 epoll 来实现高效的 I/O 事件监听和处理,同时避免了不同进程之间的干扰和冲突。

以下是 epoll 相关操作的简要介绍:

• epoll_create:创建一个 epoll 实例,内核会创建一个 eventpoll 对象,用于存储相关数据结构。该函数返回一个文件描述符,作为后续其他 epoll 系统调用的第一个参数。

• epoll_ctl:用于向 epoll 对象中添加、删除或修改所要监听的文件描述符及其相关事件。通过指定不同的操作类型(如 EPOLL_CTL_ADD、EPOLL_CTL_DEL、EPOLL_CTL_MOD)来实现相应的功能。

• epoll_wait:阻塞等待 epoll 监控的事件中已发送的事件。内核会将发生的事件赋值到提供的 epoll_event 结构体数组中。如果在给定的超时时间内有事件发生,返回事件的数量;如返回 0 表示超时;小于 0 表示出错。

整个过程结合 TCP 三次握手、四次挥手以及文件读取等操作如下(以服务器端为例):

1. 服务器创建监听套接字(使用 socket 函数)。

2. 调用 bind 函数将套接字与特定的地址和端口绑定。

3. 调用 listen 函数使套接字进入监听状态,准备接受客户端连接请求。

4. 服务器进程调用 epoll_create 创建一个 epoll 实例,获得 epoll 文件描述符 epfd。

5. 通过 epoll_ctl 将监听套接字添加到 epoll 实例中,注册感兴趣的事件(如可读事件 EPOLLIN)。

6. 进入事件循环,在循环中调用 epoll_wait 等待事件发生。

7. 当有新的客户端发起 TCP 三次握手,连接建立成功后,内核会将监听套接字的可读事件添加到 epoll 实例的就绪列表中。

8. epoll_wait 返回,服务器进程得知有新连接到来,通过 accept 函数接受连接,获得与客户端通信的新套接字。

9. 再次使用 epoll_ctl 将新的通信套接字添加到 epoll 实例中,注册相关事件(如可读、可写等)。

10. 后续服务器通过 epoll_wait 监测通信套接字上的事件,例如客户端发送数据导致可读事件触发。

11. 服务器读取数据进行处理,处理完毕后如果需要回复数据给客户端,则可进行写操作。

12. 当客户端关闭连接时,会触发四次挥手过程,相应的套接字上可能会有可读事件(表示对端关闭)或其他相关事件。

13. 服务器根据事件进行相应处理,如关闭套接字等。

14. 重复步骤 6 至步骤 13,以处理更多的客户端连接和事件。

在这个过程中,epoll 高效地管理着多个套接字的事件,避免了传统方式(如 select 或轮询)中需要遍历所有套接字来检查事件的低效率操作。文件读取等操作则是在有相关事件触发(如套接字可读)后进行的实际数据读取和处理。同时,通过合理地添加、删除套接字到 epoll 实例,以及处理 TCP 连接的建立和关闭,实现了对多个连接的有效管理。而 socket 创建和销毁则是根据实际的连接建立和关闭来进行的,当不再需要某个套接字时,会进行相应的关闭操作,释放相关资源。

在具体的实现中,epoll 利用红黑树来快速查找和管理注册的套接字,以及就绪列表来存储已触发事件的套接字,从而实现高效的事件通知机制。不同进程可以各自创建和使用 epoll 实例来管理属于自己的套接字,彼此不会相互影响。这种方式使得服务器能够同时处理大量并发连接,提高了系统的性能和可扩展性。

示例代码:

#include <stdio.h>  // C 标准输入输出库
#include <stdlib.h>  // C 标准库
#include <string.h>  // C 字符串操作库
#include <unistd.h>  // Unix 标准库
#include <sys/epoll.h>  // epoll 相关系统调用的头文件
#include <sys/socket.h>  // 套接字相关系统调用的头文件#define MAX_EVENTS 10  // 最大事件数量// 处理连接的函数
void handle_connection(int sockfd) {char buffer[1024];  // 接收数据的缓冲区int n = recv(sockfd, buffer, sizeof(buffer), 0);  // 从套接字接收数据if (n > 0) {  // 接收成功buffer[n] = '\0';  // 添加字符串结束符printf("Received: %s\n", buffer);  // 打印接收到的数据} else if (n == 0) {  // 客户端断开连接printf("Client disconnected\n");  // 打印提示信息} else {  // 接收出错perror("recv error");  // 打印错误信息}
}int main() {int epfd = epoll_create1(0);  // 创建 epoll 实例if (epfd == -1) {  // 创建失败perror("epoll_create1");  // 打印错误信息exit(EXIT_FAILURE);  // 退出程序}int listen_sock = socket(AF_INET, SOCK_STREAM, 0);  // 创建监听套接字if (listen_sock == -1) {  // 创建失败perror("socket");  // 打印错误信息exit(EXIT_FAILURE);  // 退出程序}struct sockaddr_in server_addr;  // 服务器地址结构体memset(&server_addr, 0, sizeof(server_addr));  // 初始化结构体为 0server_addr.sin_family = AF_INET;  // 设置地址族为 IPv4server_addr.sin_addr.s_addr = INADDR_ANY;  // 监听所有本地地址server_addr.sin_port = htons(8080);  // 设置端口为 8080(网络字节序)if (bind(listen_sock, (struct sockaddr *)&server_addr, sizeof(server_addr)) == -1) {  // 绑定套接字到地址perror("bind");  // 打印错误信息exit(EXIT_FAILURE);  // 退出程序}if (listen(listen_sock, 5) == -1) {  // 开始监听,允许 5 个连接排队perror("listen");  // 打印错误信息exit(EXIT_FAILURE);  // 退出程序}struct epoll_event event;  // epoll 事件结构体event.data.fd = listen_sock;  // 设置事件关联的文件描述符为监听套接字event.events = EPOLLIN;  // 关注可读事件if (epoll_ctl(epfd, EPOLL_CTL_ADD, listen_sock, &event) == -1) {  // 将监听套接字添加到 epoll 实例perror("epoll_ctl");  // 打印错误信息exit(EXIT_FAILURE);  // 退出程序}struct epoll_event events[MAX_EVENTS];  // epoll 事件数组while (1) {  // 无限循环int nfds = epoll_wait(epfd, events, MAX_EVENTS, -1);  // 等待 epoll 事件if (nfds == -1) {  // 等待出错perror("epoll_wait");  // 打印错误信息break;  // 退出循环}for (int i = 0; i < nfds; i++) {  // 遍历发生的事件if (events[i].data.fd == listen_sock) {  // 如果是监听套接字的事件int client_sock = accept(listen_sock, NULL, NULL);  // 接受新连接if (client_sock == -1) {  // 接受连接出错perror("accept");  // 打印错误信息} else {  // 接受连接成功event.data.fd = client_sock;  // 设置新连接的套接字event.events = EPOLLIN;  // 关注可读事件if (epoll_ctl(epfd, EPOLL_CTL_ADD, client_sock, &event) == -1) {  // 将新连接添加到 epoll 实例perror("epoll_ctl");  // 打印错误信息}}} else {  // 如果是客户端连接的事件handle_connection(events[i].data.fd);  // 处理连接}}}close(listen_sock);  // 关闭监听套接字close(epfd);  // 关闭 epoll 实例return 0;  // 程序正常结束返回 0
}

以下是这段代码的实现链路分析:

  1. 在 main 函数中,首先使用 epoll_create1 函数创建一个 epoll 实例,并获取其文件描述符 epfd 。如果创建失败,会打印错误信息并退出程序。
  2. 使用 socket 函数创建一个监听套接字 listen_sock ,用于接收客户端的连接请求。如果创建失败,同样会打印错误并退出。
  3. 初始化服务器地址结构体 server_addr ,设置地址族、监听的本地地址和端口。
  4. 通过 bind 函数将监听套接字与地址绑定,通过 listen 函数开始监听,指定队列中允许等待连接的最大数量。
  5. 配置一个 epoll_event 结构体 event ,将监听套接字与关注的可读事件 EPOLLIN 关联,并使用 epoll_ctl 将监听套接字添加到 epoll 实例中进行监控。
  6. 进入一个无限循环,通过 epoll_wait 函数等待 epoll 事件的发生。
  7. 当有事件发生时,通过遍历返回的事件数组 events 来处理。
    • 如果是监听套接字的事件,使用 accept 函数接受新的客户端连接,获取新的客户端套接字 client_sock 。若接受连接成功,再次配置 epoll_event 结构体,并将新的客户端套接字添加到 epoll 实例中进行监控。
    • 如果是客户端套接字的事件,调用 handle_connection 函数处理客户端的连接,在函数中通过 recv 函数接收数据,并根据接收结果进行相应的处理。
  8. 循环结束后,关闭监听套接字和 epoll 实例。

总的来说,这段代码实现了一个基于 epoll 的简单服务器,能够接受客户端连接并处理客户端发送的数据。

复制重新生成

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

“序列优化探究:最长上升子序列的算法发现与应用“

最长上升子序列 最长上升子序列是指在一个给定序列中&#xff0c;找到一个最长的子序列&#xff0c;使得子序列中的元素单调递增。例如&#xff0c;序列 [1, 3, 5, 4, 7] 的最长上升子序列是 [1, 3, 5, 7]&#xff0c;长度为4。 这是一个经典的动态规划问题。 假设dp[i]表示…

大学食堂管理系统

摘 要 随着信息技术的飞速发展和高校规模的不断扩大&#xff0c;大学食堂作为高校日常运营的重要组成部分&#xff0c;其管理效率和服务质量直接影响到师生的日常生活和学习。传统的食堂管理方式&#xff0c;如手工记录、纸质菜单、人工结算等&#xff0c;不仅效率低下&#x…

动手学深度学习(Pytorch版)代码实践 -计算机视觉-37微调

37微调 import os import torch import torchvision from torch import nn import liliPytorch as lp import matplotlib.pyplot as plt from d2l import torch as d2l# 获取数据集 d2l.DATA_HUB[hotdog] (d2l.DATA_URL hotdog.zip,fba480ffa8aa7e0febbb511d181409f899b9baa5…

每日一题——Python代码实现PAT乙级1048 数字加密(举一反三+思想解读+逐步优化)五千字好文

一个认为一切根源都是“自己不够强”的INTJ 个人主页&#xff1a;用哲学编程-CSDN博客专栏&#xff1a;每日一题——举一反三Python编程学习Python内置函数 Python-3.12.0文档解读 目录 初次尝试 再次尝试 代码点评 代码结构 时间复杂度 空间复杂度 优化建议 我要更强…

Nacos 2.x 系列【15】数据源插件支持达梦、Oracel、PostgreSQL......

文章目录 1. 概述2. 持久层机制2.1 固定语句2.2 数据源插件 3. 案例演示3.1 编译已实现插件3.2 自定义插件3.3 数据库初始化3.4 插件引入3.4.1 方式一&#xff1a;引入到源码3.4.2 方式二&#xff1a;插件加载目录 3.5 修改配置3.6 测试 1. 概述 在实际项目开发中&#xff0c;…

https://curl.trillworks.com不能用的解决方法

gitee源码:https://gitee.com/Project0ne/curlconverter 首先打开上面的链接 然后下载文件 下载文件到本地 然后安装node.js(Node.js official website.)不会的自行百度,这里不做过多赘述。 在curlconverter文件夹下面打开终端(在文件夹下面右键-在终端打开) 输入 npm…

仓颉语言的编译和构建

一、cjc 使用 cjc是仓颉编程语言的编译命令&#xff0c;其提供了丰富的功能及对应的编译选项&#xff0c;本章将对基本使用方法进行介绍。 cjc-frontend &#xff08;仓颉前端编译器&#xff09;会随 cjc 一起通过 Cangjie SDK 提供&#xff0c;cjc-frontend 能够将仓颉源码编…

SSL/TLS、SSH、IPSec等安全协议的工作原理和实现方式

SSL/TLS、SSH、IPSec是三种广泛应用于网络通信中的安全协议&#xff0c;它们各自有不同的工作原理和实现方式。 SSL/TLS&#xff08;Secure Sockets Layer / Transport Layer Security&#xff09; 工作原理深入分析 1. 握手阶段 协议协商&#xff1a;客户端首先发送一个“Cl…

图像反转入门

文章目录 1.实验目的2.需求3.代码4.运行结果图 1.实验目的 熟练掌握图像像素操作API 2.需求 自己构造一个纯黑图像,通过多种方法进行反转,最终生成一个纯白图像 3.代码 """ Time : 2024/6/23 下午3:46 Author : chensong File : 自己创建一个图像并…

Minillama3->dpo训练

GitHub - leeguandong/MiniLLaMA3: llama3的迷你版本,包括了数据,tokenizer,pt的全流程llama3的迷你版本,包括了数据,tokenizer,pt的全流程. Contribute to leeguandong/MiniLLaMA3 development by creating an account on GitHub.https://github.com/leeguandong/MiniLL…

[保姆级教程]uniapp自定义导航栏

文章目录 导文隐藏默认导航栏&#xff1a;全局隐藏当前页面隐藏 添加自定义导航栏视图&#xff1a;手写导航栏组件导航栏 导文 在 UniApp 中&#xff0c;自定义导航栏通常涉及到隐藏默认的导航栏&#xff0c;并在页面顶部添加自定义的视图组件来模拟导航栏的功能。 隐藏默认导航…

C++11 标准库头文件模拟实现

系列文章目录 文章目录 系列文章目录前言● 智能指针模板● Vector1. 简单版本2. X 总结 前言 暂不考虑支持多线程 常用STL的简单实现&#xff0c;主要内容百行左右完成&#xff0c;意在理解STL的原理 ● 智能指针模板 SharedPtr #include <assert.h> #include <ato…

用python打印——九九乘法表

# 定义外层循环的控制变量 i 1 while i < 9:# 定义内层循环的控制变量j 1while j < i:# 内层循环的print语句不要换行&#xff0c;通过\t制表符对齐print(f"{j} * {i} {j * i}\t", end)j 1i 1print() # print空内容&#xff0c;就是输出一个换行以下是…

文本三剑客

文本三剑客 sed awk grep grep就是查找文本当中的内容&#xff0c;扩展正则表达式。 sed sed是一种流编辑器&#xff0c;一次处理一行内容。 如果只是展示&#xff0c;会放到缓冲区&#xff08;模式空间&#xff09;&#xff0c;展示结束之后&#xff0c;会从模式空间把操作结…

[15] 使用Opencv_CUDA 模块实现基本计算机视觉程序

使用Opencv_CUDA 模块实现基本计算机视觉程序 CUDA提供了出色的接口,发挥GPU的并行计算能力来加速复杂的计算应用程序利用CUDA和Opencv的功能实现计算机视觉应用1. 对图像的算术和逻辑运算 两个图像相加#include <iostream> #include "opencv2/opencv.hpp" #i…

Linux运维面试--yum安装和编译安装区别

风吹哪页读哪页&#xff0c;花开何时看何时。 目录 # 1.安装方式差异 ## 1.1 yum安装 ## 1.2 源码编译安装 # 2.优缺点分析 ## 2.1 yum安装优缺点 ### 2.1.1 yum安装优点 ### 2.1.2 yum安装缺点 ## 2.2 源码安装优缺点 ### 2.2.1 源码安装优点 ### 2.2.2 源码安装缺点…

JS 实现复制文本到剪贴板

方式一&#xff1a;使用 Clipboard API 方式 /** 将文本复制到剪贴板* param e 要复制的内容*/ copyTextToClipboard(e) {const navClipboard navigator.clipboardif (!navClipboard) {console.log(浏览器不支持 Clipboard API 方式)return}navClipboard.writeText(e).then((…

主数据驱动的数据治理:技术解析与实践探索

数字化转型行业小伙伴可以加入我的星球&#xff0c;初衷成为各位数字化转型参考库&#xff0c;星球内容每周更新 个人工作经验资料全部放在这里&#xff0c;包含数据治理、数据要素、数据质量、数据安全、元数据、主数据、企业架构、DCMM、DSMM、CDGA、CDGP等各种数据相关材料 …

使用Python脚本预测天气预报的技术指南

一、引言 随着大数据和机器学习技术的快速发展&#xff0c;天气预报的准确性得到了显著提升。Python作为一种强大的编程语言&#xff0c;提供了丰富的库和工具&#xff0c;使得构建和训练预测模型变得更加容易。本文旨在介绍如何使用Python脚本进行天气预报的预测&#xff0c;…

抖音多功能全自动引流工具,支持评论关注私信留痕点赞等,让你的抖音粉丝暴涨!

随着短视频行业的火爆&#xff0c;越来越多的人开始关注抖音这个平台。然而&#xff0c;如何在抖音上获得更多的关注和粉丝&#xff0c;成为了许多人面临的难题。为了帮助大家解决这个问题&#xff0c;今天我们将为大家推荐一款抖音多功能全自动引流脚本&#xff0c;这款脚本可…