day39

IO操作主要包括两类:

本地IO:本地IO是指本地的文件读取等操作,本地IO的优化主要是在操作系统中进行,我们对于本地IO的优化作用十分有限

网络IO:网络IO指的是在进行网络操作时需要等待用户的输入及传输的等待等,网络IO的优化需要我们自己进行,而我们对于网络IO的优化主要在等待用户输入时程序可以继续运行

IO阻塞模型

1.什么是IO阻塞模型:在我们使用socket创建客户端、服务端时,如果不对 他们执行其他操作,那么客户端的recv、send和服务器端的accept、send、recv等都是阻塞的,只有等到有数据传输过来或者有客户端连接过来时才会操作,否则就会进入等待状态,这种模型就是IO阻塞模型

2.IO阻塞模型缺点:当执行到recv时,如果对象并没有发送数据,程序阻塞了,无法执行其他任务

3.解决方案以及问题:

1).多线程或多进程,

当客户端并发量非常大的时候,服务器可能就无法开启新的线程或进程,如果不对数量加以限制 服务器就崩溃了

2)线程池或进程池

首先限制了数量 保证服务器正常运行,但是问题是,如果客户端都处于阻塞状态,这些线程也阻塞了

3)协程:

使用一个线程处理所有客户端,当一个客户端处于阻塞状态时可以切换至其他客户端任务

非阻塞IO模型

1.什么是非阻塞:非阻塞IO即 在执行recv 和accept时 不会阻塞 可以继续往下执行

2.解决方案以及问题:

如何使用:

将server的blocking设置为False 即设置非阻塞

 

存在的问题 :

这样一来 你的进程 效率 非常高 没有任何的阻塞

很多情况下 并没有数据需要处理,但是我们的进程也需要不停的询问操作系统 会导致CPU占用过高

3.案例:

服务端:

import socket
import time

server = socket.socket()
server.bind(("127.0.0.1",1688))
server.listen()
server.setblocking(False) # 默认为阻塞    设置为False 表示非阻塞

# 用来存储客户端的列表
clients = []

# 链接客户端的循环
while True:
    try:
        client,addr = server.accept()   # 接受三次握手信息
        # print("来了一个客户端了.... %s" % addr[1])
        # 有人链接成功了
        clients.append(client)
    except BlockingIOError as e:
        # print("还没有人连过来.....")
        # time.sleep(0.5)
        # 服务你的客人去
        for c in clients[:]:
            try: # 可能这个客户端还没有数据过来
                # 开始通讯任务
                data = c.recv(2048)
                c.send(data.upper())
            except BlockingIOError as e:
                print("这个客户端还不需要处理.....",)

            except ConnectionResetError:
                # 断开后删除这个客户端
                clients.remove(c)
        print("=======================",len(clients))

客服端:

import socket

client = socket.socket()
client.connect(("127.0.0.1",1688))

while True:
    msg = input("msg:").strip()
    if not msg:
        continue
    try:
        client.send(msg.encode("utf-8"))
        recv_msg = client.recv(2048)
        print(recv_msg.decode("utf-8"))
    except ConnectionResetError:
        print("客户端意外关闭")
        break

多路复用IO模型

1.多路复用:多路复用IO模型指的是多个TCP连接使用一个或者少量的线程来实现通信的IO模型,在IO非阻塞模型中,我们是通过自己不停的使用send()或者recv()来不停的询问是否有数据需要进行操作,在多路复用IO模型中,我们使用select统一的来进行询问,并将可以进行操作的对象放到一个列表中进行统一管理,并且select还可以区分那些是可以发送数据的对象,哪些是可以接收数据的对象,并放在不同的列表中进行统一管理

 

select模块的使用和介绍

服务端

import socket
import time
import select


server = socket.socket()
server.bind(("127.0.0.1",1688))
server.listen()
# server.setblocking(False) # 默认为阻塞    设置为False 表示非阻塞

"""
参数1   rlist   里面存储需要被检测是否可读(是否可以执行recv)的socket对象 
参数2   wlist   里面存储需要被检测是否可写(是否可以执行send)的socket对象 
参数3   xlist 存储你需要关注异常条件  忽略即可
参数4   timeout  检测超时时间  一段时间后还是没有可以被处理的socket 那就返回空列表  
返回值:  三个列表
1    已经有数据到达的socket对象 
2    可以发送数据的socket对象    怎么可以发 缓冲区没有满  
3    忽略....
"""
rlist = [server,]
wlist = []

# 要发送的数据和socket
msgs = []
while True:
    ras,was,_ = select.select(rlist,wlist,[])  # 阻塞直到socket可读或是可写
    # 处理可读的socket
    for s in ras:
        if s == server:
            client,addr = server.accept()
            rlist.append(client)
        else:
            try:
                # 收数据
                data = s.recv(2048)
                if not data:
                    raise ConnectionResetError()
                wlist.append(s)
                # s.send(data.upper())
                # 将要发送的数据和socket 保存起来
                msgs.append((s,data))
            except ConnectionResetError:
                s.close()
                rlist.remove(s)
                if s in wlist:wlist.remove(s)

    # 处理可写的socket
    for s in was:
        for msg in msgs[:]:
            if msg[0] == s:
                s.send(msg[1].upper())
                # 发送成功之后 删除已经无用的数据 并且需要将socket从wlist列表中删除
                # 不删除会造成死循环 因为socket 一直处于可写状态
                msgs.remove(msg)
                wlist.remove(s)

客户端

import socket

client = socket.socket()
client.connect(("127.0.0.1",1688))
while True:
    msg = input("msg:")
    if not msg:continue
    client.send(msg.encode("utf-8"))
    print(client.recv(2048).decode("utf-8"))

 

多路复用的缺点:

使用多路复用解决了在非阻塞IO中出现的CPU占用过高的问题,但是在多路复用中也出现了几个问题:

    • 使用select时最多只能处理1024个客户端,如果数量多与此值,那么就会直接就会报错

    • 如果发送的数据量特别大的情况下只能处理一个客户端,其它的客户端只能进行等待

posted @ 2019-06-10 23:48  呼吸决定丶  阅读(98)  评论(0)    收藏  举报