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 端
#跟上面的同樣