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

news2024/9/17 7:16:32

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 event

since 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 to

monitor——告诉 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 sys


def 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.stdin
    epoll.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()
                    return
            elif fd == sys.stdin.fileno():
                try:
                    data = input()  # 服务器发消息给客户端
                except EOFError:  # 按下 ctrl+d 让服务器断开
                    print("I want to go")
                    new_client.close()
                    s.close()
                    return
                new_client.send(data.encode('utf8'))

        # Move these outside the loop
    new_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 sys


def tcp_client():
    if len(sys.argv) == 1:
        return
    client = 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.stdin
    epoll.register(client.fileno(), select.EPOLLIN)
    epoll.register(sys.stdin.fileno(), select.EPOLLIN)
    while True:
        # 谁的缓冲区有数据 就填写进events
        events = 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.coloradmin.cn/o/1203208.html

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

相关文章

轻盈创新,气膜体育馆

气膜体育馆采用高强度、高柔性的薄膜材料为主要构建元素。其制作过程包括将膜材的外沿固定在地面基础或屋顶结构周边,并搭配智能化的机电设备,通过吹气实现室内空间的密闭。利用密闭空间内的气压支撑原理,当室内气压大于外部气压时&#xff0…

介绍公司的软文怎么写

软文推广成为企业提高知名度和市场竞争力的主要方式之一,通过软文推广,公司能够被更多消费者熟知并在他们心中留下深刻印象,一篇好的软文,不仅能传递公司的产品和服务信息,还可以传递出公司的理念、文化等,…

postgresql数据库优化

目录 概要 优化方法 硬件知识 CPU及服务器体系结构 内存 硬盘 文件系统及I/O调优 文件系统的崩溃恢复 Ext2文件系统 Ext3文件系统 Ext4文件系统 XFS文件系统 Barriers I/O I/O调优的方法 SSD的Trim优化 数据库性能视图 Linux监控工具 数据库内存优化 大页内存配置 vacuum…

C++:对象成员方法的使用

首先复习一下const : //const: //Complex* const pthis1 &ca; //约束指针自身 不能指向其他对象 // pthis1 &cb; err //pthis1->real; //const Complex* const pthis1 &ca;//指针指向 指针自身 都不能改 //pthis1->real; 只可读 …

Jenkins 搭建

GitLab GitLab安装 https://gitlab.cn/install/?versionce CentOS 下安装 1. 安装和配置必须的依赖项 在 CentOS 7上,下面的命令也会在系统防火墙中打开 HTTP、HTTPS 和 SSH 访问。这是一个可选步骤,如果您打算仅从本地网络访问极狐GitLab&#xf…

网易有道上线“易魔声” 开源语音合成引擎 用户可免费下载使用

网易有道上线“易魔声” 开源语音合成引擎 用户可免费下载使用 刚刚,我们上线了「易魔声」开源语音合成(TTS)引擎!🎉🎉🎉 「易魔声」,是一款有道自研TTS引擎,目前支持中…

PNAS | 蛋白质结构预测屈服于机器学习

今天为大家介绍的是来自James E. Rothman的一篇短文。今年的阿尔伯特拉斯克基础医学研究奖表彰了AlphaFold的发明,这是蛋白质研究历史上的一项革命性进展,首次提供了凭借序列信息就能够准确预测绝大多数蛋白质的三维氨基酸排列的实际能力。这一非凡的成就…

react函数式组件props形式子向父传参

父组件中定义 子组件中触发回调传值 import { useState } from "react"; function Son(params) {const [count, setCount] useState(0);function handleClick() {console.log(params, paramsparamsparamsparamsparamsparams);params.onClick(111)setCount(count 1…

leetcode每日一题复盘(11.13~11.19)

leetcode 435 无重叠区间 本题和射气球最小箭数大同小异,但是这一题没做出来,难就难在题目如何理解:移除区间最小数量,使剩下的区间不重叠 那么本质上就是求最少有多少个重叠区间,把重叠区间去掉剩下的区间即不重叠 这里有两种做…

智慧工地管理云平台源码,Spring Cloud +Vue+UniApp

智慧工地源码 智慧工地云平台源码 智慧建筑源码支持私有化部署,提供SaaS硬件设备运维全套服务。 互联网建筑工地,是将互联网的理念和技术引入建筑工地,从施工现场源头抓起,最大程度的收集人员、安全、环境、材料等关键业务数据&am…

安防监控系统EasyCVR v3.4.0版本首页界面更新调整功能大汇总

安防视频监控/视频集中存储/云存储/磁盘阵列EasyCVR平台可拓展性强、视频能力灵活、部署轻快,可支持的主流标准协议有国标GB28181、RTSP/Onvif、RTMP等,以及支持厂家私有协议与SDK接入,包括海康Ehome、海大宇等设备的SDK等。平台可拓展性强、…

你知道调试一个 Web 的 Android 应用有多麻烦吗 AndroidStudio uniapp Capacitor

你知道调试一个 Web 的 Android 应用有多麻烦吗 AndroidStudio uniapp Capacitor 用的 uniapp 写的页面,全是坑,各种坑,生命周期不触发等。但由于已经做完大部分内容了,也不好换了。 我用的是 capacitor h5 > Android 的方式…

猫罐头怎么选择?精选的5款口碑好的猫罐头推荐!

猫罐头因其成分约80%为水分,对于不喜欢喝水的猫咪来说,正是可以用来补充水分的替代方案。 而近年来市面上也有越来越多讲究食用安全性的猫罐头,像是强调无添加多余加工品、或是不含谷物成分等的商品。但也因为种类过多,让铲屎官容…

【现场问题】datax中write部分为Oracle的时候插入clolb类型字段,插入的数据为string且长度过场问题

datax的Oraclewriter 报错显示查询报错展示查找datax中的数据插入模块 报错显示 occurred during batching: ORA-01704: string literal too long 查询报错展示 基本上查到的都是这样的,所以锁定是clob的字段类型的问题,而且是只有Oracle出问题&#…

vue2【计算属性】

目录 1:计算属性的作用 2:代码示例 3:特点 4:好处 1:计算属性的作用 计算属性指的是通过将属性经过运算,最终得到一个属性值,这个属性值可以在method节点下和模板结构中被使用。 2&#x…

未来之选:为什么向量数据库是您的数据管理利器

文章目录 前言什么是向量数据库?向量数据库的机制向量数据库的优点‍查询向量数据库 什么是向量Embedding?Amazon OpenSearch Service总结 前言 向量数据库擅长处理复杂的高维数据,正在彻底改变商业世界的数据检索和分析。它们执行相似性搜索…

从零基础到精通:Flutter开发的完整指南

💂 个人网站:【工具大全】【游戏大全】【神级源码资源网】🤟 前端学习课程:👉【28个案例趣学前端】【400个JS面试题】💅 寻找学习交流、摸鱼划水的小伙伴,请点击【摸鱼学习交流群】 第一部分:入…

CSRF 漏洞实战

CMS创建新用户 方法&#xff1a;攻击者可以利用 XSS 触发 CSRF 攻击。因为&#xff0c;可以利用 JS 发送 HTTP 请求。经过研究受害网站的业务流程&#xff0c;可以构造如下代码&#xff1a; 代码&#xff1a; <script> xmlhttp new XMLHttpRequest(); xmlhttp.open(&qu…

SQLServer添加Oracle链接服务器

又一次在项目中用到了在SQLServer添加Oracle链接服务器&#xff0c;发现之前文章写的也不太好使&#xff0c;那就再总结一次吧。 1、安装OracleClient 安装64位&#xff0c;多数SQLServer是64位&#xff0c;所以OracleClient也安装64位的&#xff1b; 再一个一般安装的Oracl…

小米路由器4A千兆版刷入OpenWRT并远程访问

小米路由器4A千兆版刷入OpenWRT并远程访问 文章目录 小米路由器4A千兆版刷入OpenWRT并远程访问前言1. 安装Python和需要的库2. 使用 OpenWRTInvasion 破解路由器3. 备份当前分区并刷入新的Breed4. 安装cpolar内网穿透4.1 注册账号4.2 下载cpolar客户端4.3 登录cpolar web ui管理…