首页 > 编程语言 >利用Python select模块实现多路I/O复用

利用Python select模块实现多路I/O复用

时间:2023-12-23 10:02:39浏览次数:49  
标签:socket Python outputs 复用 server 模块 接字 select

在开发网络服务时,能够同时处理多个网络连接是非常重要的。传统的方法是为每个连接创建一个新线程或进程,但这在大规模时可能会导致资源耗尽。更高效的做法是使用I/O多路复用,让一个线程能够监视多个文件描述符的状态变化。在Python中,我们可以通过select模块来实现这一功能。本文将介绍如何使用select模块构建一个多客户端的网络服务。

理解I/O多路复用

I/O多路复用允许单个进程监视多个文件描述符,一旦某个文件描述符就绪(例如,一个套接字可以进行非阻塞读取或写入),相应的操作可以被执行。这意味着一个进程可以同时管理多个活动的网络连接,而不是为每个连接分别使用独立的进程或线程。

select模块提供了访问操作系统的select()函数的接口,它是实现I/O多路复用的传统方法之一。除了select()函数,操作系统还提供了其他更高级的函数,如pollepoll,在Python中也有相应的模块。

使用select模块

接下来,我们将通过Python的select模块创建一个简单的聊天服务器,它可以同时服务多个客户端。

创建服务器

我们的服务器将使用非阻塞套接字,并利用select来检测何时可以从套接字读取数据,或者何时可以向套接字写入数据,而不会导致阻塞。

import select
import socket
import sys

HOST = '127.0.0.1'  # Standard loopback interface address (localhost)
PORT = 65432        # Port to listen on (non-privileged ports are > 1023)

# 创建TCP/IP套接字
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.setblocking(0)

# 绑定套接字到端口
server_address = (HOST, PORT)
print('starting up on {} port {}'.format(*server_address))
server.bind(server_address)

# 监听传入连接
server.listen(5)

# 设置输入、输出套接字列表
inputs = [server]
outputs = []

while inputs:
    # 等待至少一个套接字准备好处理
    readable, writable, exceptional = select.select(inputs, outputs, inputs)

    # 处理输入
    for s in readable:
        if s is server:
            # 新连接
            connection, client_address = s.accept()
            print('new connection from', client_address)
            connection.setblocking(0)
            inputs.append(connection)
        else:
            # 有数据到达
            data = s.recv(1024)
            if data:
                # A readable client socket has data
                print('received {} from {}'.format(data, s.getpeername()))
                if s not in outputs:
                    outputs.append(s)
            else:
                # Interpret empty result as closed connection
                print('closing', client_address)
                if s in outputs:
                    outputs.remove(s)
                inputs.remove(s)
                s.close()

    # 处理输出
    for s in writable:
        next_msg = "Your message has been received"
        print('sending {!r} to {}'.format(next_msg, s.getpeername()))
        s.send(next_msg.encode())
        outputs.remove(s)

    # 处理异常情况
    for s in exceptional:
        print('handling exceptional condition for', s.getpeername())
        # 停止监听连接上的输入
        inputs.remove(s)
        if s in outputs:
            outputs.remove(s)
        s.close()

这段代码首先创建了一个非阻塞的TCP服务器套接字,并监听指定的端口。通过一个无限循环,我们调用select函数等待套接字的状态改变。select返回三个列表:第一个列表包含可以读取的套接字,第二个列表包含可以写入的套接字,第三个列表包含可能有错误的套接字。

当服务器套接字准备好接受新连接时,它被添加到inputs列表中,这意味着我们可以在没有阻塞的情况下接受新的连接。当一个已连接的套接字准备好读取时,我们从客户端接收数据。如果通道可以接受数据而不阻塞,则向客户端发送响应。

连接服务器

客户端可以使用标准的网络套接字来连接服务器并发送消息。服务器将处理来自多个客户端的连接和消息。

import socket

HOST, PORT = '127.0.0.1', 65432
data = 'Hello, world!'

with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
    sock.connect((HOST, PORT))
    sock.sendall(bytes(data + "\n", "utf-8"))
    received = str(sock.recv(1024), "utf-8")

print(f"Sent:     {data}")
print(f"Received: {received}")

这个简单的客户端连接到我们定义的服务器地址和端口,并发送一个字符串,然后等待接收并打印来自服务器的响应。

结论

使用select模块进行多路I/O复用可以让您的Python程序更有效地处理多个网络连接,而无需为每个连接创建新的线程或进程。这样,您可以构建能够扩展到数百甚至数千并发连接的网络应用程序,而不会耗尽系统资源。

尽管select模块提供的是比较低层的API,但它在编写网络服务时仍然是一个非常有用的工具。在实际的生产环境中,您可能会选择使用更高级的异步I/O模块(如asyncio),但理解select模块的工作原理对于深入理解网络事件处理非常有价值。

标签:socket,Python,outputs,复用,server,模块,接字,select
From: https://blog.51cto.com/u_15288375/8944388

相关文章

  • python之列表常用方法
    常用方法:函数名说明len(list)返回列表元素个数max(list)返回列表中元素最大值min(list)返回列表中元素最小值list(tup)将元组转换为列表list.append(obj)添加obj对象到列表的末尾list.count(obj)返回obj在列表中出现的次数list..extend(seq)在列表中添加指定序列(是序列,不单只列表),函......
  • python基础007----递归函数&闭包&装饰器
    一、递归函数1、递归函数概念    直接或间接的调用自身的函数,称为递归函数。每调用一次自身,相当于复制一份该函数,只不过参数有变化,参数的变化,就是重要的结束条件。2、递归函数实例#####递归函数######1、普通实现:计算n!=1*2*3*4*5*6*...*nn=int(input('普通实现阶乘,......
  • Python+Selenium框架实战系列003----测试数据分离与ddt技术&断言
    一、测试数据分离1、新建testData文件夹,新建login_data.py文件,如下所示:   2、在login_datas.py文件中存放测试用例数据,如下所示:#正常场景success_data={"mobile":"17839196010","pwd":"duhui94619"}#异常用例--手机号异常phone_data=[{"mobile":&......
  • python自动化学习笔记5-----allure测试报告
    1、运行测试报告 2、allure注解的使用  3、优化测试报告之添加对应的标签 4、注解的使用     5、yaml文件格式 6、更改logo(1)allure目录下找到allure.yml的文件,增加插件    (2)在插件目录下添加要展示的图片    (3)修改styles.cs......
  • python自动化学习笔记6-----jekins环境搭建及使用
        msi版本安装后,要去电脑服务里面设置为自启动,否则重启电脑后使用不了。  web自动化1、实现linux部署jekins,window运行自动化代码,不在同一个机器上运行在执行机(自己的电脑上)访问jekins网址进行相应设置        运行后,进行连接,连接成功后,小......
  • python自动化学习笔记4-----pytest单元测试框架
            ......
  • Plotly,一个超强的Python可视化库!
    数据可视化是数据分析和探索的一个重要方面,它有助于深入了解数据集中的潜在模式、趋势和关系。Plotly则是一个功能强大且多功能的Python库,提供了广泛的工具来创建交互式且具有视觉吸引力的绘图。它支持多种图表类型,包括散点图、折线图、条形图等。Plotly的独特之处在于它能......
  • 封装Detours用于Python中x64函数hook
    Detours代码仓库:https://github.com/microsoft/Detoursx64写一个任意地址hook要比x86麻烦的多,所以这里直接封装框架来用于x64的hook。Detours是微软发布的一个APIhook框架,同时支持x86和x64,看文档说也支持ARM和ARM64的Windows。编译文档Detours翻了下github,并没有发现什么编......
  • 搭建 OpenCV 的 Python 开发环境
    一.安装Anaconda Anaconda(官方网站)就是可以便捷获取包且对包能够进行管理,同时对环境可以统一管理的发行版本。Anaconda包含了conda、Python在内的超过180个科学包及其依赖项。 1.下载安装文件 官网下载太慢,好在有清华大学镜像站:https://mirrors.tuna.tsinghua.edu.cn/......
  • 封装Detours用于Python中x64函数hook
    Detours代码仓库:https://github.com/microsoft/Detoursx64写一个任意地址hook要比x86麻烦的多,所以这里直接封装框架来用于x64的hook。Detours是微软发布的一个APIhook框架,同时支持x86和x64,看文档说也支持ARM和ARM64的Windows。编译文档Detours翻了下github,并没有发现什么......