【Python基础】网络编程之Epoll使用一(符实操:基于epoll实现的实时聊天室)

00

🌈欢迎来到Python专栏
🙋🏾‍♀️作者介绍:前PLA队员 目前是一名普通本科大三的软件工程专业学生
🌏IP坐标:湖北武汉
🍉 目前技术栈:C/C++、Linux系统编程、计算机网络、数据结构、Mysql、Python(目前在学)
🍇 博客介绍:通过分享学习过程,加深知识点的掌握,也希望通过平台能认识更多同僚,如果觉得文章有帮助,请您动动发财手点点赞,本人水平有限,有不足之处欢迎大家扶正~
🍓 最后送大家一句话共勉:知不足而奋进,望远山而前行。愿大家都能早日进大厂实现财富自由~

网络编程之Epoll使用

  • 1.什么是epoll
    • 1.1通俗例子说明:
    • 1.2 epoll实现过程介绍
  • 2.epoll相关参数介绍
  • 3.基于epoll实现的实时聊天室
    • 运行结果 :

1.什么是epoll

“epoll”是输入/输出事件通知的系统调用。它是 Linux 内核提供的一项功能,用于有效处理大量文件描述符或套接字。“epoll”在需要监视许多 I/O 操作的情况下特别有用,例如在处理大量并发连接的服务器中。

以下是关于“epoll”的一些关键点:

  1. 效率: 与“select”和“poll”等旧机制不同,“epoll”旨在随着文件描述符的数量而有效扩展。它特别适用于具有大量开放套接字的方案。

  2. 事件驱动: ‘epoll’ 是事件驱动的,这意味着当文件描述符上发生特定事件时,它可以通知您的程序。事件可以包括可供读取的数据、可供写入的空间或文件描述符上的错误。

  3. 边沿触发和电平触发模式:** “epoll”支持边沿触发和电平触发模式。在边缘触发模式下,仅当文件描述符的状态发生更改时,才会触发事件。在关卡触发模式下,只要条件成立,就会触发事件。

  4. 可扩展性: ‘epoll’ 以其可扩展性而闻名。它可以有效地处理大量文件描述符,而不会出现旧机制中的性能下降。

  5. 系统调用: 与 ‘epoll’ 相关的主要系统调用是 ‘epoll_create’、‘epoll_ctl’ 和 ‘epoll_wait’。

“epoll”的使用通常出现在高性能网络服务器中,例如 Web 服务器或代理,在这些服务器中,处理大量并发连接对于效率至关重要。

需要注意的是,虽然 ‘epoll’ 是特定于 Linux 的,但其他操作系统也有类似的机制,但名称不同,例如 FreeBSD 和 macOS 上的 ‘kqueue’

1.1通俗例子说明:

“epoll”就像一个繁忙的办公楼的智能接待员。想象一下,你有很多房间(文件描述符或套接字),人们(数据或事件)一直在来来去去。

  1. 效率: 智能接待员(带有“epoll”的 Linux 内核)不会浪费时间不断检查每个房间。相反,它确切地知道哪些房间发生了一些重要的事情。

  2. 事件驱动: 当房间内发生重要事件(例如要读取的新数据或要写入的空间)时,智能接待员会立即通知您。你不必一直问每个房间是否有变化。

  3. 通知类型: 当重要的事情只发生一次(边缘触发)或只要是真的(级别触发)时,智能接待员就可以通知您。这就像告诉你什么时候有人进入房间,或者什么时候有人在那里。

  4. 处理多个房间: 即使您有很多房间(大量文件描述符或套接字),聪明的接待员也擅长跟踪所有房间而不会不知所措。

  5. 智能系统呼叫: 要与智能接待员合作,您可以采取特殊操作,例如告诉接待员开始关注新房间(“epoll_create”)、要求它注意房间的某些事件(“epoll_ctl”)和等待通知(“epoll_wait”)。

因此,简单来说,“epoll”是 Linux 中的一个智能系统,它可以帮助程序有效地管理和跟踪同时发生的许多事情,例如在不减慢速度的情况下处理大量互联网连接。这就像拥有一个智能助手,可以准确地告诉您在繁忙的办公室中何时何地发生事情。

1.2 epoll实现过程介绍

  1. 创建“epoll”实例:
  • 首先使用“epoll_create()”或“epoll_create1()”系统调用创建一个“epoll”实例。这将返回与“epoll”实例关联的文件描述符。
  1. 注册文件描述符:
  • 告诉“epoll”实例要监视哪些文件描述符(套接字,在网络上下文中)以及您感兴趣的事件(例如,读取、写入或错误事件)。这是使用“epoll_ctl()”系统调用完成的。
  • 您可以在一次调用中注册对多个文件描述符和事件的兴趣。
  1. 等待事件:
  • 然后,程序使用“epoll_wait()”系统调用来等待事件。
  • ‘epoll_wait()’ 阻止程序,直到一个或多个注册事件发生。
  1. 处理事件:
  • 当事件发生时,‘epoll_wait()’ 返回,您将获得有关事件的信息。
  • 然后,您可以循环访问返回的事件,并根据事件类型(例如,读取或写入数据)执行必要的操作。
  1. 边沿触发与电平触发:
  • ‘epoll’ 支持边沿触发和电平触发模式。
  • 在边缘触发模式下,仅当文件描述符的状态发生变化时,您才会收到通知,而不一定在数据可用时通知。
  • 在电平触发模式下,只要条件成立,您就会收到通知。
  1. 修改和注销文件描述符:**
  • 您可以动态修改正在监控的文件描述符集,或使用“epoll_ctl()”取消注册它们。
  1. 关闭“epoll”实例:
  • 完成后,使用“close()”系统调用关闭“epoll”实例。

关键思想是“epoll”提供了一种有效的方法来管理大量文件描述符的 I/O 事件,而无需持续轮询。它允许程序是事件驱动的,仅在有活动时响应,而不是主动检查更改。这样可以提高资源使用效率,并为同时处理多个连接的应用程序提供更好的性能。

一般步骤1.  Create an epoll object——创建 1 个 epoll 对象2.  Tell the epoll object to monitor specific events on specific sockets— —告诉 epoll 对象,在指定的 socket 上监听指定的事件3.  Ask the epoll object which sockets may have had the specified eventsince the last query——询问 epoll 对象,从上次查询以来,哪些 socket发生了哪些指定的事件4.  Perform some action on those sockets——在这些 socket 上执行一些操作5.  Tell the epoll object to modify the list of sockets and/or events tomonitor——告诉 epoll 对象,修改 socket 列表和(或)事件,并监控6.  Repeat steps 3 through 5 until finished——重复步骤 3-5,直到完成7.  Destroy the epoll object——销毁 epoll 对象

2.epoll相关参数介绍

import select 导入 select 模块epoll = select.epoll() 创建一个 epoll 对象epoll.register(文件句柄,事件类型) 注册要监控的文件句柄和事件事件类型:
select.EPOLLIN 可读事件select.EPOLLOUT 可写事件select.EPOLLERR 错误事件select.EPOLLHUP 客户端断开事件
epoll.unregister(文件句柄) 销毁文件句柄epoll.poll(timeout) 当文件句柄发生变化,则会以列表的形式主动报告给用户进程,timeout为超时时间,默认为-1,即一直等待直到文件句柄发生变化,如果指定为 1那么 epoll 每 1 秒汇报一次当前文件句柄的变化情况,如果无变化则返回空
epoll.fileno() 返回 epoll 的控制文件描述符(Return the epoll control file descriptor) epoll.modfiy(fineno,event) fineno 为文件描述符 event 为事件类型 作用是修改文件描述符所对应的事件epoll.fromfd(fileno)1 个指定的文件描述符创建 1 个 epoll 对象
epoll.close() 关闭 epoll 对象的控制文件描述符

3.基于epoll实现的实时聊天室

  • 服务器代码:
#!/usr/bin/python
# author X_Dragon
# E-mail:3270895551@qq.com
# @Time : 2023/11/13 14:21
# 即时聊天室
import socket
import select
import sysdef tcp_server():s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)addr = ("175.178.47.72", 2001)print(addr)s.bind(addr)  # 绑定端口 此时并没有激活s.listen(128)  # listen时 端口才会激活new_client, client_addr = s.accept()  # 这里的new_client是指tcp服务器分配给客户端单独的服务print("[客户端add:%d]", client_addr)epoll = select.epoll()  # 创建一个epoll对象# 让epoll健=监控new_client sys.stdinepoll.register(new_client.fileno(), select.EPOLLIN)epoll.register(sys.stdin.fileno(), select.EPOLLIN)while True:# 谁的缓冲区有数据,就填写到events,events是列表里边存的是元组,(fd,事件)events = epoll.poll(-1)for fd, event in events:if fd == new_client.fileno():data = new_client.recv(100)if data:print(f"接收到地址为{client_addr}发送的信息:{data.decode('utf8')}")else:print(f"地址为{client_addr}的客户端已断开链接")new_client.close()returnelif fd == sys.stdin.fileno():try:data = input()  # 服务器发消息给客户端except EOFError:  # 按下 ctrl+d 让服务器断开print("I want to go")new_client.close()s.close()returnnew_client.send(data.encode('utf8'))# Move these outside the loopnew_client.close()s.close()if __name__ == '__main__':tcp_server()
  • 客户端代码
#!/usr/bin/python
# author X_Dragon
# E-mail:3270895551@qq.com
# @Time : 2023/11/13 14:39
import socket
import select
import sysdef tcp_client():if len(sys.argv) == 1:returnclient = socket.socket(socket.AF_INET, socket.SOCK_STREAM)dest_addr = ("175.178.47.72", 2001)client.connect(dest_addr)epoll = select.epoll()  # 创建一个epoll对象# 让epoll监控new_client sys.stdinepoll.register(client.fileno(), select.EPOLLIN)epoll.register(sys.stdin.fileno(), select.EPOLLIN)while True:# 谁的缓冲区有数据 就填写进eventsevents = epoll.poll(-1)for fd, event in events:if fd == client.fileno():data = client.recv(200)if data:print("客户端[%d]接收到服务器消息:%s", dest_addr, data.decode('utf8'))else:print("对方断开了...")elif fd == sys.stdin.fileno():data = input()  # 客户端端说话 发给对方client.send(data.encode('utf8'))client.close()if __name__ == '__main__':tcp_client()

运行结果 :

01

创作不易 点赞支持~
000

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

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

相关文章

Java学习之路 —— Day2(OOP)

文章目录 1. 方法2. OOP2.1 static2.2 单例模式2.3 继承2.4 多态 3. 常用API3.1 包3.2 String3.3 ArrayList 1. 方法 方法定义时要使用public static修饰,这是和C最不同的地方,因为java都是基于类执行的。 Java的参数传递机制是值传递,即传…

记录第一次利用CVE-2023-33246漏洞实现RocketMQ宿主机远程代码执行的兴奋

我依然记得自己第一次发现xss漏洞时候的兴奋: 我也记得自己第一次发现sql输入时候的快乐: 直到最近我终于收获了人生的第一个远程代码执行漏洞的利用(RCE:remote code execute),虽然这个漏洞的危害远超过了前两个,但是快乐不如前…

ctf之流量分析学习

链接:https://pan.baidu.com/s/1e3ZcfioIOmebbUs-xGRnUA?pwd9jmc 提取码:9jmc 前几道比较简单,是经常见、常考到的类型 1.pcap——zip里 流量分析里有压缩包 查字符串或者正则表达式,在包的最底层找到flag的相关内容 我们追踪…

C#动态拦截并覆盖第三方进程的函数,实现函数篡改(外挂)

今天在看之前收藏的一个pdf文档(介绍C#外挂的相关知识的),结合网上的东西及个人的理解才有了这篇文章。 参考文章: 【精选】一文带解读C# 动态拦截覆盖第三方进程中的函数(外挂必备)_zls365365的博客-CSDN博客 DotNetDetour - …

NOIP 2017 宝藏----Java题解

目录 NOIP 2017 宝藏 题目描述 输入描述: 输出描述: 输入 输出 说明 输入 输出 说明 备注: 代码实现: NOIP 2017 宝藏 时间限制:C/C 1秒,其他语言2秒 空间限制:C/C 262144K,其他语言524288K 64bit IO For…

阿里云 OSS使用介绍

1、什么是阿里云 OSS? OSS 为 Object Storage Service,即对象存储服务。是阿里云提供的海量、安全、低成本、高可靠的云存储服务。 OSS 具有与平台无关的 RESTful API 接口,可以在任意应用、任意时间、任意地点 存储与访问 任何类型的数据。…

Java编程--单例模式(饿汉模式/懒汉模式)/阻塞队列

前言 逆水行舟,不进则退!!! 目录 单例模式 饿汉模式: 懒汉模式: 什么是阻塞队列 什么是高内聚 低耦合 阻塞队列的实现 单例模式 单例模式(Singleton Pattern)是一种常见…

11. 深度学习——强化学习

机器学习面试题汇总与解析——强化学习 本章讲解知识点 什么是强化学习 围棋举例 强化学习的两个特点和一个核心 最简单的强化学习算法 一个完整的强化学习问题 进一步深入强化学习的核心 本专栏适合于Python已经入门的学生或人士,有一定的编程基础。本专栏适…

GPU Microarch 学习笔记【2】Unified Memory

目录 1. M3 Dynamic Caching 2. Unified Memory 3. Unified Memory是如何处理page fault的 4. Unified Memory Page Fault的相关论文 M3 Dynamic Caching 最新的Apple M3 芯片最亮眼的可能是支持dynamic caching,如下图所示。 具体说来就是传统的GPU分配内存时&…

C语言从入门到精通之【printf和scanf函数】

printf()是输出函数,scanf()是输入函数,但是它们的工作原理几乎相同。两个函数都使用格式字符串和参数列表。 printf()函数的格式 printf( 格式字符串, 待打印项1, 待打印项2,…);待打印项1、待打印项2等都是要打印的项。它们可以是变量、常量&#xff…

计算机视觉中目标检测的数据预处理

本文涵盖了在解决计算机视觉中的目标检测问题时,对图像数据执行的预处理步骤。 首先,让我们从计算机视觉中为目标检测选择正确的数据开始。在选择计算机视觉中的目标检测最佳图像时,您需要选择那些在训练强大且准确的模型方面提供最大价值的图…

CentOS 7镜像下载;VMware安装CentOS 7;解决新安装的虚拟机没有网络,无法ping通网络的问题

CentOS 7镜像下载;VMware安装CentOS 8.5;解决新安装的虚拟机没有网络,无法ping通网络的问题 CentOS 8.5镜像下载VMware安装CentOS 7解决新安装的虚拟机没有网络,无法ping通网络的问题写入配置文件 CentOS 8.5镜像下载 阿里提供的…

软件工程分析报告07测试计划书——基于Paddle的肝脏CT影像分割

目录 测试计划书 1. 引言 2. 测试目标 3. 测试方法 3.1 黑盒测试 (1)等价类划分: (2)边界值分析: (3)因果图: ​编辑(4)错误推测法 3.2 白盒测试 测试用例!! 4. 测试环境 5. 测试计划 6…

Docker - DockerFile

Docker - DockerFile DockerFile 描述 dockerfile 是用来构建docker镜像的文件!命令参数脚本! 构建步骤: 编写一个dockerfile 文件docker build 构建成为一个镜像docker run 运行脚本docker push 发布镜像(dockerhub&#xff0…

Vue3-TypeScript-Threejs:导入外部的glb格式3D模型

一、直接上代码&#xff0c;在vue3-typescript-threejs 项目 导入外部的glb格式3D模型 极简代码&#xff0c;快速理解 <template><div ref"container"></div></template><script lang"ts" setup>import { onMounted, ref …

阶段七-Day01-SpringMVC

一、Sping MVC的介绍 1. 使用Front(前端)设计模式改写代码 1.1 目前我们的写法 目前我们所写的项目&#xff0c;持久层、业务层的类都放入到Spring容器之中了。他们之间需要注入非常方便&#xff0c;只需要通过Autowired注解即可。 但是由于Servlet整个生命周期都是被Tomca…

数据结构—二叉树的模拟实现(c语言)

目录 一.前言 二.模拟实现链式结构的二叉树 2.1二叉树的底层结构 2.2通过前序遍历的数组"ABD##E#H##CF##G##"构建二叉树 2.3二叉树的销毁 2.4二叉树查找值为x的节点 2.5二叉树节点个数 2.6二叉树叶子节点个数 2.7二叉树第k层节点个数 三.二叉树的遍历 3.1…

java基础-数据类型

1、变量 变量就是申请内存来存储值。也就是说&#xff0c;当创建变量的时候&#xff0c;需要在内存中申请空间。 内存管理系统根据变量的类型为变量分配存储空间&#xff0c;分配的空间只能用来储存该类型数据。 因此&#xff0c;通过定义不同类型的变量&#xff0c;可以在内…

【C++】类与对象 I

类与对象 I &#xff1a; 前言&#xff1a;&#xff08;C&#xff09;面向过程 和&#xff08;C&#xff09;面向对象 初步认识前言&#xff1a;类的引入一、类的介绍二、类的定义&#xff08;一&#xff09;class 语法&#xff08;二&#xff09;类的两种定义方式&#xff1a;…

个人网厅——销户

目录 需求文档 公积金销户类 controller层 service层 service层实现类 1.验证 &#xff08;个人账户&#xff09; 2.提交&#xff08;添加&#xff09; controller层 service层 service层实现类 3.分页查询 controller层 service层 service层实现类 4. 详情查询…