IO sock对象本质是文件描述符,什么是文件描述符,是一个非零的整数,内核区接受的数据,在用户拷贝完以后就没有了html
IO多路复用比阻塞IO的好处是能够监听多个sock对象,能处理多个链接,IO多路复用全程阻塞,能实现并发现象,必定不是同时聊,没有开多线程多进程web
什么是阻塞IO,(什么是非阻塞IO),主进程会一直卡住不能干其余事,知道对应的操做结束,非阻塞IO不会卡,缓存
阻塞IO全程阻塞,非阻塞IO,copydaty时进程阻塞,IO多路复用全程阻塞;这三个是同步IO模型,只有第四个异步IO全程无阻塞,可是实现麻烦,全程由操做系统完成(waitdata copydata)网络
同步IO只要两个过程(wait data,copy data)有一个是阻塞的就叫同步IO多线程
同步: 阻塞IO 非阻塞IO io多路复用(select epoll poll)
异步: 异步IO
IO模型有几个角色: 进程,操做系统(内核),IO都是进程的Io并发
http://www.cnblogs.com/yuanchenqi/articles/6755717.htmlapp
IO模型
进程若是有数据的交换,进程发系统调用进入内核态,内核态的数据cp到用户空间,分两个过程,wait for data ,copy data
阻塞IO

非阻塞IO

IO多路复用异步
IO multiplexing这个词可能有点陌生,可是若是我说select,epoll,大概就都能明白了。有些地方也称这种IO方式为event driven IO。咱们都知道,select/epoll的好处就在于单个process就能够同时处理多个网络链接的IO。它的基本原理就是select/epoll这个function会不断的轮询所负责的全部socket,当某个socket有数据到达了,就通知用户进程。它的流程如图:

当用户进程调用了select,那么整个进程会被block,而同时,kernel会“监视”全部select负责的socket,当任何一个socket中的数据准备好了,select就会返回。这个时候用户进程再调用read操做,将数据从kernel拷贝到用户进程。
这个图和blocking IO的图其实并无太大的不一样,事实上,还更差一些。由于这里须要使用两个system call (select 和 recvfrom),而blocking IO只调用了一个system call (recvfrom)。可是,用select的优点在于它能够同时处理多个connection。(多说一句。因此,若是处理的链接数不是很高的话,使用select/epoll的web server不必定比使用multi-threading + blocking IO的web server性能更好,可能延迟还更大。select/epoll的优点并非对于单个链接能处理得更快,而是在于能处理更多的链接。)
在IO multiplexing Model中,实际中,对于每个socket,通常都设置成为non-blocking,可是,如上图所示,整个用户的process实际上是一直被block的。只不过process是被select这个函数block,而不是被socket IO给block。socket
结论: select的优点在于能够处理多个链接,不适用于单个链接 函数
总结##################################################################################
IO就是进程有须要数据的时候才会产生IO系统调用,分两个阶段 1:wait for data;2: copy data
阻塞IO全程阻塞(进程在须要IO调用的时候,用户程序发动系统调用,从用户态转到内核态(内核态是操做系统管理,有操做硬件的权限)直到数据从内核缓存区cp到用户区,此时内核的数据直接清除),
非阻塞IO wait for data不阻塞,用户程序会隔一段时间就到内核区问问,数据准备好了没有,一次次的发起系统调用,直到有数据了,阻塞cp数据
IO多路复用:这个最大的改善是用户程序调用select函数发起系统调用阻塞等数据,等数据到了,用户进程发起系统调用cp数据,而后清除内核缓存中的数据,比IO阻塞多了个系统调用,下面的例子多个客户端聊天
就是及于此
1 阻塞IO: 全程阻塞 2 非阻塞IO:
优势:wait for data时无阻塞 缺点:1 系统调用太多 2 数据不是实时接受的 两个阶段:wait for data:非阻塞 copy data :阻塞 3 IO多路复用(监听多个链接)
sock::sock <socket.socket fd=224, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('127.0.0.1', 8800)> 224就是文件打桩符 对于文件描述符(套接字对象): 1 是一个非零整数,不会变 2 收发数据的时候,对于接收端而言,数据先到内核空间, 而后copy到用户空间,同时,内核空间数据清除。 特色:1 全程(wait for data,copy)阻塞 2 能监听多个文件描述符 实现并发 4 异步IO 全程无阻塞, 5 驱动信号 总结: 同步: 阻塞IO 非阻塞IO io多路复用 异步: 异步IO
#server端 #简单聊天,最大接受5个client排队,第一个链接后就进入while第二个,阻塞socket模块 import socket import time sock=socket.socket() sock.bind(("127.0.0.1",8800)) sock.listen(5) #sock.setblocking(False) # while 1: # try: # conn,addr=sock.accept() # 阻塞等待连接 # except Exception as e: # print(e) # time.sleep(3) # data=conn.recv(1024) # # print(data.decode("utf8")) while 1: conn,addr=sock.accept() print("server working.......") while 1: data=conn.recv(1024) print(data.decode("utf8")) send_data=input(">>>") conn.send(send_data.encode("utf8")) conn.close() #client端 import socket sock=socket.socket() sock.connect(("127.0.0.1",8800)) while 1: data=input("input>>>") sock.send(data.encode("utf8")) rece_data=sock.recv(1024) print(rece_data.decode("utf8")) sock.close()
#给予select机制实现多客户端并发聊天 若是几个客户端前后发消息过来,监控的列表中conn几个会有变化,server端会吧有变化的conn for遍历一遍回消息再 #server端 #sock是客户来链接才有变化,conn是客户发消息才有变化,主要仍是解决IO操做 import socket import time import select sock=socket.socket() sock.bind(("127.0.0.1",8800)) sock.listen(5) sock.setblocking(False) inputs=[sock,] print("sock",sock) while 1: r,w,e=select.select(inputs,[],[]) # select只监听有变化的套接字 inputs=[sock,conn1,conn2,conn3..] #开启select首先到这, print("r",r) for obj in r: # 第一次 [sock,] 第二次(客户端发消息) #[conn1,] if obj==sock:#客户端第一次链接走这条路 print('change') conn,addr=obj.accept() inputs.append(conn) # inputs=[sock,conn] else:#客户端第二次发消息走这条路 data=obj.recv(1024) print(data.decode("utf8")) send_data=input(">>>") obj.send(send_data.encode("utf8"))
#client 端
#跟上面的同样