網絡編程6(IO模型)

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 端
#跟上面的同樣
相關文章
相關標籤/搜索