網路io模型
一、網路io
輸入:recv recvfrom accept 阻塞io
輸出:send sendto sendall connect 會等待一段時間,但是卻是非阻塞io,因為是乙個主動的過程
二、網路io模型------跟socket有關
blocking io 阻塞io 平時用的、tcp、udp
nonblocking io 非阻塞io
io multiplexing io多路復用
asynchronous io 非同步io python中已經有非同步的框架
三、預備知識
再說一下io發生時涉及的物件和步驟。對於乙個network io (這裡我們以read舉例),它會涉及到兩個系統物件,乙個是呼叫這個io的process (or thread),另乙個就是系統核心(kernel)。當乙個read操作發生時,該操作會經歷兩個階段:
#1)等待資料準備 (waiting for記住這兩點很重要,因為這些io模型的區別就是在兩個階段上各有不同的情況。the data to be ready)
#2)將資料從核心拷貝到程序中(copying the data from the kernel to the process)
阻塞io(blocking io)
在linux中,預設情況下所有的socket都是blocking,乙個典型的讀操作流程大概是這樣:
一台計算機上的
所以,blocking io的特點就是在io執行的兩個階段(等待資料和拷貝資料兩個階段)都被block了。
實際上,除非特別指定,幾乎所有的io介面 ( 包括socket介面 ) 都是阻塞型的。這給網路程式設計帶來了乙個很大的問題,如在呼叫recv(1024)的同時,執行緒將被阻塞,在此期間,執行緒將無法執行任何運算或響應任何的網路請求。
乙個簡單的解決方案:
#該方案的問題是:在伺服器端使用多執行緒(或多程序)。多執行緒(或多程序)的目的是讓每個連線都擁有獨立的執行緒(或程序),這樣任何乙個連線的阻塞都不會影響其他的連線。
#改進方案:開啟多程序或都執行緒的方式,在遇到要同時響應成百上千路的連線請求,則無論多執行緒還是多程序都會嚴重佔據系統資源,降低系統對外界響應效率,而且執行緒與程序本身也更容易進入假死狀態。
#改進後方案其實也存在著問題:很多程式設計師可能會考慮使用「執行緒池」或「連線池」。「執行緒池」旨在減少建立和銷毀執行緒的頻率,其維持一定合理數量的執行緒,並讓空閒的執行緒重新承擔新的執行任務。「連線池」維持連線的快取池,盡量重用已有的連線、減少建立和關閉連線的頻率。這兩種技術都可以很好的降低系統開銷,都被廣泛應用很多大型系統,如websphere、tomcat和各種資料庫等。
#對應上例中的所面臨的可能同時出現的上千甚至上萬次的客戶端請求,「執行緒池」或「連線池」或許可以緩解部分壓力,但是不能解決所有問題。總之,多執行緒模型可以方便高效的解決小規模的服務請求,但面對大規模的服務請求,多執行緒模型也會遇到瓶頸,可以用非阻塞介面來嘗試解決這個問題。「執行緒池」和「連線池」技術也只是在一定程度上緩解了頻繁呼叫io介面帶來的資源占用。而且,所謂「池」始終有其上限,當請求大大超過上限時,「池」構成的系統對外界的響應並不比沒有池的時候效果好多少。所以使用「池」必須考慮其面臨的響應規模,並根據響應規模調整「池」的大小。
非阻塞io(non-blocking io)
所以,在非阻塞式io中,使用者程序其實是需要不斷的主動詢問kernel資料準備好了沒有。
#非阻塞io實現socket併發服務端from socket import *
import
time
s=socket(af_inet,sock_stream)
s.bind((
'127.0.0.1
',8080))
s.listen(5)
s.setblocking(false)
#設定socket的介面為非阻塞
conn_l=
del_l=
while
true:
try:
conn,addr=s.accept()
except
blockingioerror:
(conn_l)
for conn in
conn_l:
try:
data=conn.recv(1024)
ifnot
data:
continue
conn.send(data.upper())
except
blockingioerror:
pass
except
connectionreseterror:
for conn in
del_l:
conn_l.remove(conn)
conn.close()
del_l=
#客戶端
from socket import *c=socket(af_inet,sock_stream)
c.connect((
'127.0.0.1
',8080))
while
true:
msg=input('
>>: ')
ifnot msg:continue
c.send(msg.encode(
'utf-8'))
data=c.recv(1024)
print(data.decode('
utf-8
'))
但是非阻塞io模型絕不被推薦。
我們不能否則其優點:能夠在等待任務完成的時間裡幹其他活了(包括提交其他任務,也就是 「後台」 可以有多個任務在「」同時「」執行)。
但是也難掩其缺點:
#此外,在這個方案中recv()更多的是起到檢測「操作是否完成」的作用,實際作業系統提供了更為高效的檢測「操作是否完成「作用的介面,例如select()多路復用模式,可以一次檢測多個連線是否活躍。1. 迴圈呼叫recv()將大幅度推高cpu佔用率;這也是我們在**中留一句time.sleep(2)的原因,否則在低配主機下極容易出現卡機情況
#2. 任務完成的響應延遲增大了,因為每過一段時間才去輪詢一次read操作,而任務可能在兩次輪詢之間的任意時間完成。這會導致整體資料吞吐量的降低。
io多路復用(io multiplexing)
io多路復用------作業系統提供的機制 select模組是乙個**
1.程式不能干預過程
2.不同的作業系統會有差異
網路程式設計學習 io模型之io多路復用
簡而言之,就是將準備要用的檔案描述符新增到一張表裡,然後讓select等待表裡的任一描述符準備就緒 就是可以執行了 然後執行那個已經準備就緒的檔案描述符,然後把其他的沒有準備好的檔案描述符全都刪除 援引知乎上的乙個解釋 int select int maxfdpl,fd set readset,fd...
Linux網路程式設計 IO模型,IO多路復用思想
io多路復用 參考書籍 後台開發 核心技術與應用實踐 linux高效能伺服器程式設計 apue 之前嘮到了socket,嘮到了怎麼建立連線。這篇文章就嘮一下,怎麼向socket中寫資料,怎麼從socket中讀出資料以及高效的讀寫 多路io復用技術 門口坐著瞅 阻塞 一直到 來了老弟 辦事 呼叫者呼叫...
IO模型 IO多路復用
用socket 一定會用到accept recv recvfrom這些方法 正常情況下 accept recv recvfrom都是阻塞的 如果setblocking false 整個程式就變成乙個非阻塞的程式了非阻塞的特點 沒有併發程式設計的機制 是乙個同步的程式 程式不會在某乙個連線的recv或...