非阻塞套接字与IO多路复用

本文介绍非阻塞IO的概念及其在Python中的实现方式,包括使用异常处理来处理非阻塞IO产生的异常,同时介绍了如何利用IO多路复用提高并发处理效率,减少资源浪费。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

非阻塞IO
利用异常处理来处理非阻塞IO产生的异常

import socket

server = socket.socket()  # 生成一个socket对象
server.setblocking(False)  # 设置非阻塞套接字
server.bind(('127.0.0.1', 5959))  # 绑定IP 端口
server.listen(5)  # 监听数量 也就是允许连接客户端数量

# 一直接收 避免阻塞
while True:
    try:
        conn, addr = server.accept()  # 对等套接字为一个元组对象 进行元组拆包
        data = conn.recv(1024)  # 接收客户端发送的数据
    except BlockingIOError:
        pass
    except Exception as e:
        print('未知异常', e)

实现并发
并发:指一个时间段中有几个程序都处于已启动运行到运行完毕之间,且这几个程序都是在同一个处理机上运行,但任一个时刻点上只有一个程序在处理机上运行

并行:指一个时间段中有几个程序都处于已启动运行到运行完毕之间,且这几个程序是在不同的处理机上运行,并任一个时刻点上有多个程序在不同处理机上运行

import socket

server = socket.socket() # 生成一个socket对象
server.setblocking(False)  # 非阻塞IO,针对客户端连接
server.bind(('127.0.0.1', 5959))# 绑定IP 端口
server.listen(5)# 监听数量 也就是允许连接客户端数量

all_conn = [] #定义一个空列表,用来存放对等连接套接字

while True:
    try:
        conn,addr = server.accept()  #不停地生成对等连接套接字,用来接收不同客户端
        conn.setblocking(False)   #非阻塞IO,针对数据的传输
        all_conn.append(conn)  # 把套接字放进列表
    except BlockingIOError:
        pass
    except Exception as e:
        print('未知异常',e)


    for conn in all_conn:
        try:
            recv_data = conn.recv(1024)
            if recv_data:  # 如果有数据
                print(recv_data)
                conn.send(recv_data) #把数据发回客户端
            else:  #如果没有数据
                conn.close()
                all_conn.remove(conn)
        except BlockingIOError:
            pass
        except Exception as e:
            print('未知异常',e)

复用器
IO多路复用
在之前的非阻塞IO模型中,通过不断的询问来查看是否有数据,这会造成资源的浪费。

将查看的过程由主动的查询,变成交给复用器完成,这样能够更加节省系统资源,并且性能更好

import socket
import selectors  # IO多路复用器选择模块

epoll_select = selectors.EpollSelector()  # 实例化一个复用器对象epoll,linux独有
# de_select = selectors.DefaultSelector()  # 默认选择器

server = socket.socket() # 生成一个socket对象
server.bind(('127.0.0.1', 5959)) # 绑定IP 端口
server.listen(5) # 监听数量 也就是允许连接客户端数量


def f_recv(conn):
    recv_data = conn.recv(1024)  # 通过对等连接套接字接收数据
    if recv_data:
        print(recv_data)
        conn.send(recv_data)
    else:
        conn.close()


def f_accept(server):
    conn, addr = server.accept()  # 创建对等套接字
    epoll_select.register(conn, selectors.EVENT_READ, f_recv)


# 注册方法, selectors.EVENT_READ有事件发生是就会执行回调函数
epoll_select.register(server, selectors.EVENT_READ, f_accept)

while True:
    events = epoll_select.select()  # 查询复用器,只要有数据,就查出来
    # print(events)
    for key, mask in events:
        # print(key)
        func = key.data  # 函数体
        conn = key.fileobj  
        func(conn)

非阻塞套接字与IO多路复用
非阻塞套接字需要自身遍历每个对等连接套接字,并且每次都是进行的IO操作
复用器不需要进行大量的IO操作,复用器会告诉你哪个对等连接套接字有数据过来,然后再去处理即可

epoll
epoll是一个惰性事件回调,即回调过程是用户自己去调用的,操作系统只起到通知的作用。
epoll是Linux上最好的IO多路复用器,但是也只有在Linux上有,在其他的地方没有。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一逍倾城

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值