標籤:逾時 output except desc 伺服器 狀態 exce recv 個數
在python的網路編程裡,socetserver是個重要的內建模組,其在內部其實就是利用了I/O多工、多線程和多進程技術,實現了並發通訊。與多進程和多線程相比,I/O多工系統開銷小,系統不必額外再建立進程或線程,也就不需要維護這些進程或線程,從而大大減小了系統的開銷。當然,這三者不是孤立的,可以聯合使用,效果可能更好。
瞭解了IO多工,我們就來看看python中是如何使用的。Python中有一個select模組,其中提供了:select、poll、epoll三個方法,分別調用系統的 select,poll,epoll 從而實現IO多工。(下面以select方法為例)
Windows Python: 提供: selectMac Python: 提供: selectLinux Python: 提供: select、poll、epoll
注意:網路操作、檔案操作、終端操作等均屬於IO操作,對於windows只支援Socket操作,其他系統支援其他IO操作,但是無法檢測 普通檔案操作 自動上次讀取是否已經變化。
對於select方法:
控制代碼列表11, 控制代碼列表22, 控制代碼列表33 = select.select(控制代碼序列1, 控制代碼序列2, 控制代碼序列3, 逾時時間)<br>參數: 可接受四個參數(前三個必須)傳回值:三個列表 select方法用來監視檔案控制代碼,如果控制代碼發生變化,則擷取該控制代碼。1、當 參數1 序列中的控制代碼發生可讀時(accetp和read),則擷取發生變化的控制代碼並添加到 傳回值1 序列中2、當 參數2 序列中含有控制代碼時,則將該序列中所有的控制代碼添加到 傳回值2 序列中3、當 參數3 序列中的控制代碼發生錯誤時,則將該發生錯誤的控制代碼添加到 傳回值3 序列中4、當 逾時時間 未設定,則select會一直阻塞,直到監聽的控制代碼發生變化 當 逾時時間 = 1時,那麼如果監聽的控制代碼均無任何變化,則select會阻塞 1 秒,之後返回三個空列表,如果監聽的控制代碼有變化,則直接執行。
#!/usr/bin/env python# -*- coding:utf-8 -*-import selectimport threadingimport syswhile True: readable, writeable, error = select.select([sys.stdin,],[],[],1) if sys.stdin in readable: print( ‘select get stdin‘,sys.stdin.readline())
利用select實現偽同時處理多個Socket用戶端請求:服務端
#!/usr/bin/env python# -*- coding:utf-8 -*-import socketip_port = (‘127.0.0.1‘,8002)sk = socket.socket()sk.connect(ip_port)while True: inp = input(‘please input:‘).encode() sk.sendall(inp)sk.close()
此處的Socket服務端相比與原生的Socket,他支援當某一個請求不再發送資料時,伺服器端不會等待而是可以去處理其他請求的資料。但是,如果每個請求的耗時比較長時,select版本的伺服器端也無法完成同時操作。
#!/usr/bin/env python#coding:utf8‘‘‘ 伺服器的實現 採用select的方式‘‘‘import selectimport socketimport sysimport Queue#建立通訊端並設定該通訊端為非阻塞模式server = socket.socket(socket.AF_INET,socket.SOCK_STREAM)server.setblocking(0)#綁定通訊端server_address = (‘localhost‘,10000)server.bind(server_address)#將該socket變成服務模式#backlog等於5,表示核心已經接到了串連請求,但伺服器還沒有調用accept進行處理的串連個數最大為5#這個值不能無限大,因為要在核心中維護串連隊列server.listen(5)#初始化讀取資料的監聽列表,最開始時希望從server這個通訊端上讀取資料inputs = [server]#初始化寫入資料的監聽列表,最開始並沒有用戶端串連進來,所以列表為空白outputs = []#要發往用戶端的資料message_queues = {}while inputs: print(‘waiting for the next event‘) #調用select監聽所有監聽列表中的通訊端,並將準備好的通訊端加入到對應的列表中 readable,writable,exceptional = select.select(inputs,outputs,inputs)#列表中的socket 通訊端 如果是檔案呢? #監控檔案控制代碼有某一處發生了變化 可寫 可讀 異常屬於Linux中的網路編程 #屬於同步I/O操作,屬於I/O複用模型的一種 #rlist--等待到準備好讀 #wlist--等待到準備好寫 #xlist--等待到一種異常 #處理可讀取的通訊端 ‘‘‘ 如果server這個通訊端可讀,則說明有新連結到來 此時在server通訊端上調用accept,產生一個與用戶端通訊的通訊端 並將與用戶端通訊的通訊端加入inputs列表,下一次可以通過select檢查串連是否可讀 然後在發往用戶端的緩衝中加入一項,鍵名為:與用戶端通訊的通訊端,索引值為空白隊列 select系統調用是用來讓我們的程式監視多個檔案控制代碼(file descrīptor)的狀態變化的。程式會停在select這裡等待, 直到被監視的檔案控制代碼有某一個或多個發生了狀態改變 ‘‘‘ ‘‘‘ 若可讀的通訊端不是server通訊端,有兩種情況:一種是有資料到來,另一種是連結斷開 如果有資料到來,先接收資料,然後將收到的資料填入往用戶端的緩衝區中的對應位置,最後 將於用戶端通訊的通訊端加入到寫資料的監聽列表: 如果通訊端可讀.但沒有接收到資料,則說明用戶端已經斷開。這時需要關閉與用戶端串連的通訊端 進行資源清理 ‘‘‘ for s in readable: if s is server: connection,client_address = s.accept() print(‘connection from‘,client_address) connection.setblocking(0)#設定非阻塞 inputs.append(connection) message_queues[connection] = Queue.Queue() else: data = s.recv(1024).decode() if data: print(‘received "%s" from %s‘% (data,s.getpeername())) message_queues[s].put(data) if s not in outputs: outputs.append(s) else: print(‘closing‘,client_address) if s in outputs: outputs.remove(s) inputs.remove(s) s.close() del message_queues[s] #處理可寫的通訊端 ‘‘‘ 在發送緩衝區中取出響應的資料,發往用戶端。 如果沒有資料需要寫,則將通訊端從發送隊列中移除,select中不再監視 ‘‘‘ for s in writable: try: next_msg = message_queues[s].get_nowait() except Queue.Empty: print(‘ ‘,s,getpeername(),‘queue empty‘) outputs.remove(s) else: print(‘sending "%s" to %s‘% (next_msg,s.getpeername())) s.send(next_msg) #處理異常情況 for s in exceptional: for s in exceptional: print(‘exception condition on‘,s.getpeername()) inputs.remove(s) if s in outputs: outputs.remove(s) s.close() del message_queues[s]
轉載:http://www.cnblogs.com/feixuelove1009/p/5660126.html
python中的IO多工