python-非阻塞IO-多路复用

一、非阻塞IO

  1. IO模型:

    什么是IO:IO指的是输入输出,其执行速度都非常慢

    模型:指固定的套路

    IO模型就是所有可以实现输入输出的套路

  2. IO的分类:

    1. 本地IO:指的是输入输出到本地计算机,比如写入硬盘
    2. 网络IO:指的是输入输出到网络中的计算机,速度远比本地IO慢

非阻塞IO服务端:

import socket

server = socket.socket()
server.bind(('127.0.0.1',21211))
server.listen()
#设置为非阻塞IO
server.setblocking(False)
#所有客户端
clients = []

while True:
    try:
        client,addr = server.accept()
        clients.append(client)
    except BlockingIOError:
        #存储所有已经关闭的客户端
        close_ls = []
        #存储所有需要发送数据的客户端
        msg_ls = []
        for c in clients:
            try:
                data = c.recv(1024)
                if not data:
                    c.close()
                    close_ls.append(c)
                #把要发送数据的客户端和数据存储到列表中,单独发送
                msg_ls.append((c,data))
            except BlockingIOError:
                pass
            except ConnectionResetError:
                c.close()
                close_ls.append(c)

        #处理发送数据
        #已经发送完成的客户端和数据
        sended_msg = []
        for client_and_data in msg_ls:
            c = client_and_data[0]
            data = client_and_data[1]
            try:
                c.send(data.upper())
                #加入待删除表
                sended_msg.append(client_and_data)
            except BlockingIOError:
                pass
        #将已经发送成功的数据从待发送列表中删除
        #sended_msg是已经发送完成的数据
        for i in sended_msg:
            #msg_ls要发送的数据
            msg_ls.remove(i)
        sended_msg.clear()

        #把已经关闭的连接从所有客户端列表中删除
        #close_ls是所有关闭的客户端
        for i in close_ls:
            #clients是所有客户端
            clients.remove(i)
        close_ls.clear()

非阻塞IO客户端:

import socket
import os
import time
c = socket.socket()
c.connect(('127.0.0.1',21211))
while True:
    msg = "hello i am: %s" % os.getpid()
    time.sleep(1)
    if not msg:
        continue
    c.send(msg.encode('utf-8'))
    print(c.recv(1024).decode('utf-8'))

二、多路复用

  1. 什么的多路复用:指的是多个连接在复用一个线程,反过来说 一个线程处理多个连接,提高了单线程处理能力

    总结:

    多路复用提升的是单线程处理网络IO的效率

    协程提升的是单线程处理所有IO的效率

多路复用服务端:

import socket
import select
server = socket.socket()
server.bind(('127.0.0.1',21211))
server.listen()

#select 是帮我们监控连接
#需要给它传两个列表,一个是检测是否可读(是否可以执行recv),一个是检测是否可写(是否可执行send)
rlist = [server,]
wlist = []

#默认select是阻塞的,会直到有其中一个或几个需要被处理
#存储要发送的数据
msg = {}

# 返回值
# 1.可读的连接(可以执行recv)
# 2.可写的连接(可以执行send)
while True:
    readable_list, writeable_list, _ = select.select(rlist,wlist,[])
    #处理可读可写列表
    print(readable_list)
    #处理可读列表
    for c in readable_list:
        #说明当需要被处理的是服务器
        if c == server:
           client, addr = c.accept()
           #把客户端也教给select检测是否可读
           #这是client..................%s <socket.socket fd=436, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('127.0.0.1', 21211), raddr=('127.0.0.1', 59662)>
           rlist.append(client)
        else:
            print('客户端可以recv了')
            data = c.recv(1024)
            print(data.decode('utf-8'))
            # 把客户端也教给select检测是否可写
            #这是c...................%s <socket.socket fd=436, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('127.0.0.1', 21211), raddr=('127.0.0.1', 59662)>
            wlist.append(c)
            msg[c] = data
    print(writeable_list)
    print(msg)
    #处理可写列表
    for w in writeable_list:
        w.send(msg[w].upper())
        #将已经发送完成的连接从检测列表删除
        wlist.remove(w)

多路复用客户端:

import socket
import os
import time
c = socket.socket()
c.connect(("127.0.0.1",21211))

while True:
    msg = "hello i am: %s" % os.getpid()
    time.sleep(1)
    if not msg:
        continue
    c.send(msg.encode("utf-8"))
    print(c.recv(1024).decode("utf-8"))

猜你喜欢

转载自blog.csdn.net/zdc45625/article/details/85953122