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

2024-05-30 02:12

本文主要是介绍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 1024int 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;
}

这篇关于Linux学习笔记(epoll,IO多路复用)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1015295

相关文章

Linux镜像文件制作方式

《Linux镜像文件制作方式》本文介绍了Linux镜像文件制作的过程,包括确定磁盘空间布局、制作空白镜像文件、分区与格式化、复制引导分区和其他分区... 目录1.确定磁盘空间布局2.制作空白镜像文件3.分区与格式化1) 分区2) 格式化4.复制引导分区5.复制其它分区1) 挂载2) 复制bootfs分区3)

Linux服务器数据盘移除并重新挂载的全过程

《Linux服务器数据盘移除并重新挂载的全过程》:本文主要介绍在Linux服务器上移除并重新挂载数据盘的整个过程,分为三大步:卸载文件系统、分离磁盘和重新挂载,每一步都有详细的步骤和注意事项,确保... 目录引言第一步:卸载文件系统第二步:分离磁盘第三步:重新挂载引言在 linux 服务器上移除并重新挂p

Linux下屏幕亮度的调节方式

《Linux下屏幕亮度的调节方式》文章介绍了Linux下屏幕亮度调节的几种方法,包括图形界面、手动调节(使用ACPI内核模块)和外接显示屏调节,以及自动调节软件(CaliseRedshift和Reds... 目录1 概述2 手动调节http://www.chinasem.cn2.1 手动屏幕调节2.2 外接显

Linux(centos7)虚拟机没有IP问题及解决方案

《Linux(centos7)虚拟机没有IP问题及解决方案》文章介绍了在CentOS7中配置虚拟机网络并使用Xshell连接虚拟机的步骤,首先,检查并配置网卡ens33的ONBOOT属性为yes,然后... 目录输入查看ZFhrxIP命令:ip addr查看,没有虚拟机IP修改ens33配置文件重启网络Xh

linux实现对.jar文件的配置文件进行修改

《linux实现对.jar文件的配置文件进行修改》文章讲述了如何使用Linux系统修改.jar文件的配置文件,包括进入文件夹、编辑文件、保存并退出编辑器,以及重新启动项目... 目录linux对.jar文件的配置文件进行修改第一步第二步 第三步第四步总结linux对.jar文件的配置文件进行修改第一步进

linux ssh如何实现增加访问端口

《linuxssh如何实现增加访问端口》Linux中SSH默认使用22端口,为了增强安全性或满足特定需求,可以通过修改SSH配置来增加或更改SSH访问端口,具体步骤包括修改SSH配置文件、增加或修改... 目录1. 修改 SSH 配置文件2. 增加或修改端口3. 保存并退出编辑器4. 更新防火墙规则使用uf

Linux join命令的使用及说明

《Linuxjoin命令的使用及说明》`join`命令用于在Linux中按字段将两个文件进行连接,类似于SQL的JOIN,它需要两个文件按用于匹配的字段排序,并且第一个文件的换行符必须是LF,`jo... 目录一. 基本语法二. 数据准备三. 指定文件的连接key四.-a输出指定文件的所有行五.-o指定输出

Linux jq命令的使用解读

《Linuxjq命令的使用解读》jq是一个强大的命令行工具,用于处理JSON数据,它可以用来查看、过滤、修改、格式化JSON数据,通过使用各种选项和过滤器,可以实现复杂的JSON处理任务... 目录一. 简介二. 选项2.1.2.2-c2.3-r2.4-R三. 字段提取3.1 普通字段3.2 数组字段四.

Linux kill正在执行的后台任务 kill进程组使用详解

《Linuxkill正在执行的后台任务kill进程组使用详解》文章介绍了两个脚本的功能和区别,以及执行这些脚本时遇到的进程管理问题,通过查看进程树、使用`kill`命令和`lsof`命令,分析了子... 目录零. 用到的命令一. 待执行的脚本二. 执行含子进程的脚本,并kill2.1 进程查看2.2 遇到的

Linux云服务器手动配置DNS的方法步骤

《Linux云服务器手动配置DNS的方法步骤》在Linux云服务器上手动配置DNS(域名系统)是确保服务器能够正常解析域名的重要步骤,以下是详细的配置方法,包括系统文件的修改和常见问题的解决方案,需要... 目录1. 为什么需要手动配置 DNS?2. 手动配置 DNS 的方法方法 1:修改 /etc/res