Python网络编程使用select实现socket全双工异步通信功能示例

下面就是详细的 Python 网络编程使用 select 实现 socket 全双工异步通信功能的攻略。

1、什么是 select

select 是一种 I/O 多路复用机制,它可以监控多个文件描述符,等待输入或输出操作就绪,从而实现启用一个线程或一个进程就能同时管理多个连接通道。

2、select 的优劣

  • 优点:select 可以同时监听多个连接,无需通过多线程、多进程实现,节省了系统资源,提高了程序效率。
  • 缺点:select 在高并发条件下,处理效率会随着连接增多而下降,且开发难度较大。

3、使用 select 实现 socket 全双工异步通信

(1)创建套接字和绑定端口:

import socket

server = socket.socket()
server.bind(('localhost', 8888))
server.listen(5)

(2)准备 I/O 数据:

msg1 = b'Hello, from client1!'
msg2 = b'Hello, from client2!'

(3)创建 select 对象和加入列表:

import select

inputs = [server]
outputs = []

(4)循环接收和处理数据:

while True:
    # select 机制实现异步 I/O
    # 监听 inputs 中可读事件和写事件,超时时间设置为 5 秒
    rlist, wlist, elist = select.select(inputs, outputs, inputs, 5)
    # 遍历可读事件列表,接收客户端连接请求
    for s in rlist:
        if s is server:
            conn, addr = server.accept()
            print('新客户端连接:', addr)
            # 将新连接加入 inputs 中,以便监控其输入事件
            inputs.append(conn)
        else:
            # 从已连接的客户端接收数据并输出
            data = s.recv(1024)
            if data:
                print(data)
                # 将输出目标加入 outputs 列表
                outputs.append(s)
            else:
                # 如果客户端连接关闭,将其从 inputs 中移除
                inputs.remove(s)
                s.close()

    # 遍历可写事件列表,发送数据给客户端
    for s in wlist:
        if s in outputs:
            # 向连接的客户端发送数据
            s.sendall(msg2)
            # 将该连接从输出列表中删除
            outputs.remove(s)

    # 遍历异常事件列表,关闭连接并移除
    for s in elist:
        inputs.remove(s)
        if s in outputs:
            outputs.remove(s)
        s.close()

上述示例中,创建了一个服务器套接字server 和一个监听列表 inputs,将 server 添加到 inputs 列表中,实现异步监听连接请求。接下来,使用 select.select() 方法,将 inputs 中的 socket 对象分组,轮流检查每个可读或可写的套接字,并响应相应的数据,并在需要时添加或删除socket对象。这种管理方式提供了更高的并发处理能力,增加了服务器的稳定性和可用性。

示例中还可以通过数据包长度(recv(1024))或消息结束符(\n等)来控制数据的粘连度,这显然需要在数据发送方进行控制。

4、示例说明

示例1:使用 select 实现简单聊天室

# 聊天室服务端示例
import socket
import select

server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
server.bind(('localhost', 10086))
server.listen(5)

inputs = [server]
outputs = []

while True:
    rlist, wlist, elist = select.select(inputs, outputs, inputs, 5)
    for s in rlist:
        if s is server:
            conn, addr = s.accept()
            print('New connection from', addr)
            inputs.append(conn)
        else:
            try:
                data = s.recv(1024)
            except:
                data = b''

            if data:
                print(data)
                for other in inputs:
                    if other != s and other != server:
                        try:
                            other.sendall(data)
                        except:
                            pass
            else:
                inputs.remove(s)
                s.close()
    for s in wlist:
        pass
    for s in elist:
        inputs.remove(s)
        if s in outputs:
            outputs.remove(s)
        s.close()

server.close()

以上代码中,服务端创建了一个socket实例,循环接收客户端请求,并实现了基于select式的异步输入输出数据。每当一个客户端 socket 实例有数据的时候,服务端就会将这个消息广播到所有连接到的 socket 实例中。

示例2:使用 select 实现批量邮件发送

# 邮件发送客户端实例
import socket
import select

def sendmail(sender, recipient, subject, content):
    # 连接邮件服务器
    server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    server.connect(('smtp.example.com', 25))
    inputs = [server]
    outputs = []
    # 接收服务器返回信息并解码为字符串
    def recv_all(sock):
        data = b""
        while True:
            try:
                more = sock.recv(1024)
                if not more:
                    break
                data += more
            except Exception as e:
                print("对方网络不稳定,连接中断!")
                data = ""
                break
        return data.decode('utf-8')
    # 发送邮件
    rlist, wlist, elist = select.select(inputs, outputs, inputs, 10)
    server.sendall(b'HELO example.com\n')
    print(recv_all(server))
    server.sendall(b'MAIL FROM:' + sender.encode() + b'\n')
    print(recv_all(server))
    server.sendall(b'RCPT TO:' + recipient.encode() + b'\n')
    print(recv_all(server))
    server.sendall(b'DATA\n')
    print(recv_all(server))
    server.sendall(b'Subject:' + subject.encode() + b'\n')
    server.sendall(b'From:' + sender.encode() + b'\n')
    server.sendall(b'To:' + recipient.encode() + b'\n\n')
    server.sendall(content.encode() + b'\n')
    server.sendall(b'.\n')
    print(recv_all(server))
    server.sendall(b'QUIT\n')
    print(recv_all(server))
    # 关闭连接
    server.close()

if __name__ == '__main__':
    sendmail('johndoe@example.com', 'janedoe@example.com', 'test email', 'hello,world!')

以上代码中,一个邮件服务是由邮件服务器和发送者和接收者两个 socket 实例组成,每个发送 socket 实例开启 select 异步输入输出数据交换机制,读入用户的 mail 消息进行后续处理。在 select 的监听机制下,实现多任务完成信道相互隔离的通信操作。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Python网络编程使用select实现socket全双工异步通信功能示例 - Python技术站

(0)
上一篇 2023年5月19日
下一篇 2023年5月19日

相关文章

  • Python实现自定义包的实例详解

    Python实现自定义包的实例详解 在Python中,我们可以使用自定义包来组织和管理我们的代码。自定义包可以将相关的模块组织在一起,方便我们进行管理和维护。本文将详细介绍如何实现自定义包,并提供两个示例说明。 创建自定义包 要创建自定义包,我们需要按照以下步骤进行操作: 创建一个目录,用于存放自定义包的代码。 在目录中创建一个__init__.py文件,用…

    python 2023年5月14日
    00
  • python之随机数函数的实现示例

    下面是详细讲解“python之随机数函数的实现示例”的完整攻略。 简介 随机数在计算机程序中经常用到,Python 也提供了内置的随机数模块 random,它包含了多个生成随机数的函数,本文将通过实例演示 random 模块的使用。 random 模块示例 生成随机整数 可以使用 randint() 方法生成一个指定范围内的随机整数: import rand…

    python 2023年6月3日
    00
  • Linux下乱码问题的解决方案小结

    我开始讲解“Linux下乱码问题的解决方案小结”攻略。 一、乱码的原因 在Linux下,乱码问题主要是由于字符编码不同导致的。在不同的操作系统中,使用的字符编码不同,例如Windows使用的是GB2312或者GBK编码,而Linux使用的是UTF-8编码。因此在进行跨系统的文本传输或者跨系统的文件操作时,容易出现乱码问题。 二、解决方案 1. 手动设置编码 …

    python 2023年5月20日
    00
  • pandas如何使用列表和字典创建 Series

    使用pandas创建Series时,可以使用列表和字典两种方式。 使用列表创建Series 使用列表创建Series的语法如下: import pandas as pd data = [1, 2, 3, 4, 5] s = pd.Series(data) print(s) 输出结果如下: 0 1 1 2 2 3 3 4 4 5 dtype: int64 首先…

    python 2023年5月13日
    00
  • 详解python 爬取12306验证码

    接下来我将为你详细讲解“详解Python爬取12306验证码”的完整攻略。 1. 前言 在进行python爬虫时,验证码的破解常常是很重要的一步。而12306验证码的破解则是很多人首次接触验证码破解时的练手项目。本文将详细介绍如何使用Python来爬取12306的验证码。 2. 前置要求 在开始之前,需要满足以下前置要求: 安装Python 2.X或3.X版…

    python 2023年6月3日
    00
  • Python中如何引入第三方模块

    在Python中,引入第三方模块是一种常见的操作,可以大大提高程序的开发效率和功能性,下面我将介绍详细的引入第三方模块的攻略。 引入第三方模块的方法 Python引入第三方模块有多种方法,例如: 方法一:使用pip安装 pip是Python的默认包管理器,可以用来方便地安装、升级、卸载第三方模块。使用方法很简单,只需要在命令行输入以下命令: pip inst…

    python 2023年5月18日
    00
  • Python中xml和dict格式转换的示例代码

    下面是“Python中xml和dict格式转换的示例代码”的完整攻略。 1. 背景介绍 在Python的开发过程中,经常需要将XML格式的数据转换成Python的dict格式。这样可以方便地提取和操作数据。Python提供了一些标准的库,可以方便地完成XML与dict的相互转换。 2. 示例一:XML转换成Dict 假设我们有一个XML文件,内容如下: &l…

    python 2023年6月3日
    00
  • python 基于aiohttp的异步爬虫实战详解

    Python基于aiohttp的异步爬虫实战详解攻略 本文将介绍基于aiohttp实现简单的异步爬虫的步骤和方法,让您轻松掌握异步爬虫开发! 安装aiohttp 首先,我们需要安装aiohttp库,执行以下命令: pip install aiohttp 简单的异步爬虫示例 下面,我们将使用aiohttp实现简单的异步爬虫。要爬取的网址是https://www…

    python 2023年5月14日
    00
合作推广
合作推广
分享本页
返回顶部