I/O模型

I/O模型

同步、异步指提交任务方式,异步不等于阻塞,异步一般与回调联合使用

分类:

  1. 阻塞IO
  2. 非阻塞IO
  3. IO多路复用
  4. 信号驱动IO(使用较少)
  5. 异步IO

主要研究网络IO:

什么功能属于IO行为?收发消息都属于网络IO行为

阻塞IO

server

from socket import *

server=socket(AF_INET,SOCK_STREAM)
server.bind(('127.0.0.1',8080))
server.listen(5)
while True:
    conn,addr=server.accept()
    print(addr)
    while True:
        try:
            data=conn.recv(1024)
            if not data:break
            conn.sendall(data.upper())
        except ConnectionResetError:
            break

    conn.close()
server.close()
View Code

 client

from socket import *
client=socket(AF_INET,SOCK_STREAM)
client.connect(('127.0.0.1',8080))
while True:
    msg=input(">>").strip()
    if not msg:break
    client.send(msg.encode("utf-8"))
    recv=client.recv(1024)
    print(recv.decode("utf-8"))
View Code

 

非阻塞IO模型,解决IO阻塞问题,充分利用wait data时间

server

from socket import *

server=socket(AF_INET,SOCK_STREAM)
server.bind(('127.0.0.1',8080))
server.listen(5)
server.setblocking(False)#default is True
print("starting....")

rlist=[]
while True:
    try:
        conn,addr=server.accept()
        conn.setblocking(False)
        rlist.append(conn)
    except BlockingIOError:
        del_list=[]
        for conn in rlist:
            try:
                data=conn.recv(1024)
                if not data:
                    del_list.append(conn)
                    continue
                conn.send(data.upper())
            except BlockingIOError:
                continue
            except Exception as e:
                print(e)
                conn.close()
                del_list.append(conn)
        for dlist in del_list:
            rlist.remove(dlist)

client

from socket import *
client=socket(AF_INET,SOCK_STREAM)
client.connect(('127.0.0.1',8080))
while True:
    msg=input(">>").strip()
    if not msg:break
    client.send(msg.encode("utf-8"))
    recv=client.recv(1024)
    print(recv.decode("utf-8"))

多路复用IO模型,可以同时检测多个套接字IO

优点:

  可以检测多个套接字,比阻塞IO快

缺点:

  代理套接字太多后,导致很多询问无用,效率更低。linux提供pool功能。eppol可以很好解决,但是跨平台性差,windows不支持epoll

  selectors可以更加操作系统选择最优非阻塞IO

server

from socket import *
import select
server=socket(AF_INET,SOCK_STREAM)
server.bind(('127.0.0.1',8080))
server.listen(5)
server.setblocking(False)#default is True
rlist=[server]#这里为什么放server?应为也需要检测server是否有accept请求过来呀
wlist=[]
xliet=[]
dlist={}#保存接收到的数据
while True:
    rl,wl,xl=select.select(rlist,wlist,xliet,0.5)#timeout参数表示隔多久询问一次操作系统
    for sock in rl:#判断是否是rl产生数据,可能是新连接进来
        if sock==server:#有连接请求进来,需建立连接
            conn,addr=server.accept()
            print(addr)
            rlist.append(conn)#连接建立好后,放入rlist中也检测起来,即检测conn是否有数据过来
        else:#不是server肯定就是conn了,conn只有接收数据。因为rlist中只有server和conn,没其他对象
            try:
                data=sock.recv(1024)#这里不应该直接发,也经过select来处理,所以,如下
                if not data:#linux平台不会抛出异常,一直接收空字符串
                    sock.close()#关闭
                    rlist.remove(sock)#移除监控
                wlist.append(sock)#放进去后就开始检测,只要缓冲区没有满,就可以发送数据
                dlist[sock]=data#存放该conn接收到的数据,用于后面处理
            # except ConnectionResetError:#windows下,客户端断开会抛ConnectionResetError错误、
            except Exception:##检测所有异常
                sock.close()#产生异常的连接关闭掉
                rlist.remove(sock)#异常连接不再监控
    for sock in wl:#也可能是wl列表产生变化,所以进程迭代,wl列表中的conn只有发送数据一件事可干
        data=dlist[sock]#取出之前连接接收到的数据
        sock.send(data.upper())#对数据进行处理后发送
        wlist.remove(sock)#数据处理完后就不需要监控 该连接了,所以从监控列表中删除
        dlist.pop(sock)#也需从存储数据的字典中将该连接的数据删除掉
server.close()

client

from socket import *
client=socket(AF_INET,SOCK_STREAM)
client.connect(('127.0.0.1',8080))
while True:
    msg=input(">>").strip()
    if not msg:break
    client.send(msg.encode("utf-8"))
    recv=client.recv(1024)
    print(recv.decode("utf-8"))

异步IO(Asynchronous I/O)

后面爬虫项目介绍

 

posted @ 2018-05-17 08:36  丫丫625202  阅读(126)  评论(0编辑  收藏  举报