IO模型

一:blocking IO(阻塞IO)

在linux中,默认情况下所有的socket都是blocking;

import socket

sock=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
sock.setsockopt(socket.SQL_SOCKET,socket.SO_REUSEADDR,1)#操作系统会在服务器socket被关闭或服务器进程终止后马上释放该服务器的端口,否则操作系统会保留几分钟该端口
sock.bind(("127.0.0.1",9090))#绑定IP地址和端口
sock.listen(5)#设置挂起的链接数
while 1:#链接循环
    conn,sddr=sock.accept()
    print("链接:",conn)
    while 1:#通信循环
        try:#针对window系统里的链接断开所引发的异常
            data=conn.recv(1024)
            if not data:continue#应对linux系统,当客户端断开链接,会不断的收空消息
            print(data.decode("utf8"))

        except Exception:
View Code

 blocking IO的特点就是在IO执行的两个阶段都被block;

二:non-blocking IO(非阻塞IO)

 

import socket
sock=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
sock.setsockopt(socket.SQL_SOCKET,socket.SO_REUSEADDR,1)
sock.bind(("127.0.0.1",8080))
sock.listen(5)
sock.setblocking(False)#默认是True
while 1:
    try:
        conn,addr=sock.accept()#当内核没有返回数据的时候,就返回错误
        print("conn:",conn)
        data=conn.recv(1024)#当内核没有返回数据的时候,就返回错误
        print(str(data,"utf8"))
    except Exception as e:
        print(e)
View Code

 总结:可以发送多次系统调用

优点:wait for data时无阻塞

缺点:<1>:系统调用太多<2>:数据不是实时接收

copy data:阻塞

三:multiplexing(IO多路复用)监听多个连接

import socket
import select

sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.bind(("127.0.0.1", 8080))
sock.listen(5)
sock.setblocking(False)

inputs = [
    sock,
]

while 1:
    r, w, e = select.select(inputs, [], [])#数据被拷贝到用户空间后,内核空间数据清除,然后继续监听内核空间,如有再有数据发过来,就发生了从0到有的变化
    for obj in r:
        if obj == sock:
            conn, addr = obj.accept()#当select到消息后,再去取内核里的数据,如果不取,就一直在内核空间
            inputs.append(conn)
            print("conn:",conn)
        else:
            try:#在window上,子链接断开触发的异常
                data = obj.recv(1024)#当select到消息后,再去取内核里的数据,如果不取,就一直在内核空间
                if not data:#linux上,子链接断开,会收到一个空
                    inputs.remove(obj)#删除子链接
                    continue
                print(data.decode("utf8"))
                send_data = input(">>> ")
                obj.send(send_data.encode("utf8"))
            except Exception:
                inputs.remove(obj)#删除子链接
View Code

 

注意1:select函数返回结果中如果有文件可读了,那么进程就可以通过调用接收accept()或recv()来让kernel将位于内核中准备到的数据copy到用户区;

2: select的优势在于可以处理多个连接,不适用于单个连接;

对于文件描述符(套接字对象):①是一个非零整数,不会改变;②收发数据的时候,对于接收端而言,数据先到内核空间,然后copy到用户空间,同时、内核空间数据清除;

特点:1:全程(wait for data,copy)阻塞
2:能监听多个文件描述符(链接),实现并发
四:Asynchronous I/O(异步IO)全程无阻塞

异步IO在请求完成时,通过将文件句柄设为有信号状态来通知应用程序,或者应用程序通过GetOverlappedResult察看IO请求是否完成,也可以通过一个事件对象来通知应用程序;
用户进程发起read操作之后,立刻就可以开始去做其它的事。而另一方面,从kernel的角度,当它受到一个asynchronous read之后,首先它会立刻返回,所以不会对用户进程产生任何block。然后,kernel会等待数据准备完成,然后将数据拷贝到用户内存,当这一切都完成之后,kernel会给用户进程发送一个signal,告诉它read操作完成了。
五:IO模型比较分析

阻塞IO:会一直阻塞住主进程直到操作完成

非阻塞IO:当内核准备数字中,会立即返回(如果没数据,就返回错误)

同步:在waitting for data 或者copy data的任意一个阶段有阻塞,就是同步的

异步:全程无阻塞



加深理解:
http://www.cnblogs.com/yuanchenqi/articles/6755717.html

http://www.cnblogs.com/Anker/p/3254269.html

https://www.zhihu.com/question/19732473?sort=created&page=2

IO在计算机中指Input/Output,也就是输入和输出;由于程序和运行时数据是在内存中驻留,由CPU这个超快的计算核心来执行,涉及到数据交换的地方,通常是磁盘、网络等,就需要IO接口。
posted @ 2017-05-10 15:12  姚大运  阅读(135)  评论(0)    收藏  举报