昨天開始講到通過設定setblocking實現當沒有接收的時候我們會每隔一段時間去看是否收到,從而是空置過程的程式歸我們使用。
然後今天我們將引入select模組,來實現監測的效果。
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。
注意1:select函式返回結果中如果有檔案可讀了,那麼程序就可以通過呼叫accept()或recv()來讓kernel將位於核心中準備到的資料copy到使用者區。
注意2: select的優勢在於可以處理多個連線,不適用於單個連線
首先是最基本的乙個select的呼叫
import這個地方會存在乙個現象,當我們連線客戶端後,會反覆的列印hello和》socket
import
select
sk=socket.socket()
sk.bind((
"127.0.0.1
",9904))
sk.listen(5)
while
true:
r,w,e=select.select([sk,],,,5)
for i in
r:
#conn,add=i.accept()
#print(conn)
print("
hello")
print('
>>>>>>')
#*************************client.py
import
socket
sk=socket.socket()
sk.connect((
"127.0.0.1
",9904))
while 1:
inp=input("
>>
").strip()
sk.send(inp.encode(
"utf8"))
data=sk.recv(1024)
print(data.decode("
utf8
"))
而不是直接只迴圈》
所以就引入了乙個新的知識:觸點方式
1.水平觸發(11111100000011111)設定為1或0時進行觸發,只要是0或1就一直觸發
2.邊緣觸發,只有電位訊號由0變1或是由1變0的時候會觸發
關於selcet的多路復用問題:
select
select最早於2023年出現在4.2bsd中,它通過乙個select()系統呼叫來監視多個檔案描述符的陣列,當select()返回後,該陣列中就緒的檔案描述符便會被核心修改標誌位,使得程序可以獲得這些檔案描述符從而進行後續的讀寫操作。
select目前幾乎在所有的平台上支援
select的乙個缺點在於單個程序能夠監視的檔案描述符的數量存在最大限制,在linux上一般為1024,不過可以通過修改巨集定義甚至重新編譯核心的方式提公升這一限制。
另外,select()所維護的儲存大量檔案描述符的資料結構,隨著檔案描述符數量的增大,其複製的開銷也線性增長。同時,由於網路響應時間的延遲使得大量tcp連線處於非活躍狀態,但呼叫select()會對所有socket進行一次線性掃瞄,所以這也浪費了一定的開銷。
如何實現多路進行通訊呢?
請看例項:
server端併發聊天
#其實今天的概念好難懂啊,腦子糊糊的,明天去吃個肉,應該思路會更清晰一些。***********************server.py
import
socket
import
select
sk=socket.socket()
sk.bind((
"127.0.0.1
",8801))
sk.listen(5)
inputs=[sk,]
while
true:
r,w,e=select.select(inputs,,,5)
(len(r))
for obj in
r:
if obj==sk:
conn,add=obj.accept()
(conn)
else
: data_byte=obj.recv(1024)
print(str(data_byte,'
utf8'))
inp=input('
回答%s號客戶》
'%inputs.index(obj))
obj.sendall(bytes(inp,
'utf8'))
print('
>>
',r)
#***********************client.py
import
socket
sk=socket.socket()
sk.connect((
'127.0.0.1
',8801))
while
true:
inp=input("
>>>>")
sk.sendall(bytes(inp,
"utf8"))
data=sk.recv(1024)
print(str(data,'
utf8
'))
第55天 爬蟲的介紹
by 閒歡 作為程式設計師,相信大家對 爬蟲 這個詞並不陌生,身邊常常會有人提這個詞,在不了解它的人眼中,會覺得這個技術很高階很神秘。不用著急,我們的爬蟲系列就是帶你去揭開它的神秘面紗,探尋它真實的面目。網路爬蟲 又被稱為網頁蜘蛛,網路機械人 是一種按照一定的規則,自動地抓取全球資訊網資訊的程式或者...
python第25天 學習python第25天
今天是在尚學堂學習python第25天今天學習了使用者管理,許可權管理 使用者管理 1.使用者的登入與退出 語法 mysql h hostname p port u username p dbname e h hostname 指定要連線mysql的主機名或者ip hostname就是具體的主機名或...
python學習第7天
崔鑫陽 2019.225 課堂檢測題 輸入兩個數 求出他們之間所有的素數 把這些素數放在 乙個列表裡 求這個列表裡素數的和 以及 最大值 和最小值 寫到乙個 裡 num 1 int input 輸入第乙個數 num 2 int input 輸入第二個數 if num 1 num 2 turn num...