python 網路程式設計----非阻塞或非同步程式設計
From: http://blog.chinaunix.net/uid-20730371-id-765038.html
非阻塞或非同步程式設計
Forking和threading的方法非常簡單,通過使用SocketServer服務類的min-in類就可以實現。forking只適用於類Unix平臺;threading需要注意記憶體共享的問題。
非同步I/O如果底層的方法來實現是有點困難的。要簡單點,我們可以考慮使用標準庫中的框架或Twisted(Twisted是一個非常強大的非同步網路程式設計的框架)。
一、用ScoketServer實現Forking和threading
下面我們使用兩個例子來分別建立forking伺服器和threading伺服器。
Forking 伺服器:
from SocketServer import TCPServer, ForkingMixIn, StreamRequestHandler
class Server(ForkingMixIn, TCPServer): pass
class Handler(StreamRequestHandler):
def handle(self):
addr = self.request.getpeername()
print 'Got connection from', addr
self.wfile.write('Thank you for connecting')
server = Server(('', 1234), Handler)
server.serve_forever()
threading伺服器:
from SocketServer import TCPServer, ThreadingMixIn, StreamRequestHandler
class Server(ThreadingMixIn, TCPServer): pass
class Handler(StreamRequestHandler):
def handle(self):
addr = self.request.getpeername()
print 'Got connection from', addr
self.wfile.write('Thank you for connecting')
server = Server(('', 1234), Handler)
server.serve_forever()
二、使用select實現非同步I/O
所謂非同步I/O,打個比方,就是如果一大群人都想你聽他說話,那麼你就給他們每人一分鐘的時間說,大家輪流說,沒說完的待會兒輪到時再繼續說。也就是一個時間片的方法。
要實現非同步I/O,我們可以通過使用框架asyncore/asynchat或Twisted,它們都是基於select函式或poll函式(poll只適於類Unix系統)的。select和poll函式都來自select模組。
select 函式要求三個必須序列作為引數和一個可選的以秒為單位的超時值。序列中是表示檔案描述符的整數值,它們是我們要等待的連線。這三個序列是關於輸入、輸出和 異常條件的。如果超時值沒有給出的話,select將處於阻塞狀態(也就是等待)直到有檔案描述符準備動作。如果超時值給出了,那麼select只阻塞給 定的時間。如果超時值是0的話,那麼將不阻塞。select返回的值是一個由三個序列組成的元組,它們分別代表相應引數的活動的子集。例如,第一個序列返 回的是用於讀的輸入檔案描述符構成的序列。
序列可以包含檔案物件(不適於Windows)或socket。下面這個例子建立一個使用 select去服務幾個連線的伺服器(注意:服務端的socket自身也提供給了select,以便於它能夠在有新的連線準備接受時發出訊號通知)。這個 伺服器只是簡單地列印接受自客戶端的資料。你可以使用telnet(或寫一個基於socket的簡單的客戶端)來連線測試它。
select server
import socket, select
s = socket.socket()
host = socket.gethostname()
port = 1234
s.bind((host, port))
s.listen(5)
inputs = [s]
while True:
rs, ws, es = select.select(inputs, [], [])
for r in rs:
if r is s:
c, addr = s.accept()
print 'Got connection from', addr
inputs.append(c)
else:
try:
data = r.recv(1024)
disconnected = not data
except socket.error:
disconnected = True
if disconnected:
print r.getpeername(), 'disconnected'
inputs.remove(r)
else:
print data
三、Twisted
Twisted 是針對Python的一個事件驅動的網路框架,最初是為了網路遊戲而開發的,但是現在被應用於各類網路軟體。用Twisted,你可以實現事件處理器,非 常類似用GUI工具包(Tk, GTK, Qt, wxWidgets)。這部分我將介紹一些基本的概念和演示如何使用Twisted來做一些相對簡單的 網路程式設計。Twisted是非常強大的框架並提供了大量的支援,如:Web伺服器和客戶端、 SSH2, SMTP, POP3, IMAP4, AIM, ICQ, IRC, MSN,Jabber, NNTP, DNS等等。
早先我們所寫的基於socket的伺服器,它們都有一個顯示的事件迴圈:尋找新的連線和新的資料;基於SocketServer的伺服器有一個隱含的迴圈:尋找連線和為連線建立處理器。但時處理器仍然時顯示的讀資料。
而 Twisted使用了更多的基於事件的方式。要寫一個基本的伺服器,你要實現事件處理器,它處理諸如一個新的客戶端連線、新的資料到達和客戶端連線中斷等 情況。在Twisted中,你的事件處理器定義在一個protocol中;你也需要一個factory,當一個新的連線到達時它能夠構造這個 protocol物件,但是如果你僅僅想建立一個自定義的Protocol類的例項的話,你可以使用來自Twisted的factory,Factory 類在模組twisted.internet.protocol中。當你寫你的protocol時,使用 twisted.internet.protocol模組中的Protocol作為你的父類。當你得到一個連線時,事件處理器 connectionMade被呼叫;當你丟失了一個連線時,connectionLost被呼叫。從客戶端接受資料使用處理器 dataReceived。但是你不能使用事件處理策略向客戶端傳送資料;要向客戶端傳送資料,你可以使用self.transport,它有一個 write方法。它也有一個client屬性,其中包含了客戶端的地址(主機名和埠)。
下面這個例子是一個Twisted版的伺服器。 其中例項化了Factory並設定了它的protocol屬性以便它知道使用哪個protocol與客戶端通訊(這就是所謂的你的自定義 protocol)。然後你使用factory開始監聽指定的埠,factory通過例項化的protocol物件處理連線。監聽使用reactor模 塊中的listenTCP函式。最後,你通過呼叫reactor模組中的run函式來開始伺服器。
from twisted.internet import reactor
from twisted.internet.protocol import Protocol, Factory
# 定義你Protocol類
class SimpleLogger(Protocol):
def connectionMade(self):
print 'Got connection from', self.transport.client
def connectionLost(self, reason):
print self.transport.client, 'disconnected'
def dataReceived(self, data):
print data
# 例項化Factory
factory = Factory()
# 設定factory的protocol屬性以便它知道使用哪個protocol與客戶端通訊(這就是所謂的你的自定義
# protocol)
factory.protocol = SimpleLogger
# 監聽指定的埠
reactor.listenTCP(1234, factory)
# 開始執行主程式
reactor.run()
為 你的處理目的而寫一個自定義的protocol是很容易的。模組twisted.protocols.basic中包含了幾個有用的已存在的 protocol,其中的LineReceiver執行dataReceived並在接受到了一個完整的行時呼叫事件處理器lineReceived。如 果當你在接受資料時除了使用lineReceived,還要做些別的,那麼你可以使用LineReceiver定義的名為rawDataReceived 事件處理器。下面是一使用LineReceiver的伺服器例子:
from twisted.internet import reactor
from twisted.internet.protocol import Factory
from twisted.protocols.basic import LineReceiver
class SimpleLogger(LineReceiver):
def connectionMade(self):
print 'Got connection from', self.transport.client
def connectionLost(self, reason):
print self.transport.client, 'disconnected'
def lineReceived(self, line):
print line
factory = Factory()
factory.protocol = SimpleLogger
reactor.listenTCP(1234, factory)
reactor.run()
相關文章
- [譯] 非同步程式設計:阻塞與非阻塞非同步程式設計
- Java 網路程式設計 —— 非阻塞式程式設計Java程式設計
- Socket程式設計中的同步、非同步、阻塞和非阻塞(轉)程式設計非同步
- 阻塞式程式設計和非阻塞式程式設計區別程式設計
- NIO非阻塞程式設計小案例程式設計
- 一文徹底搞定(阻塞/非阻塞/同步/非同步)網路IO、併發程式設計模型、非同步程式設計模型的愛恨情仇非同步程式設計模型
- IO multiplexing 與 非阻塞網路程式設計程式設計
- 玩轉 PHP 網路程式設計全套阻塞與非阻塞 IOPHP程式設計
- 【進階之路】併發程式設計(三)-非阻塞同步機制程式設計
- 阻塞/非阻塞讀寫總結、tcp網路程式設計的本質、muduo::Buffer設計簡介TCP程式設計
- Java網路程式設計和NIO詳解5:Java 非阻塞 IO 和非同步 IOJava程式設計非同步
- Java 網路程式設計 —— 實現非阻塞式的伺服器Java程式設計伺服器
- 程式設計師的“非程式設計師”之路程式設計師
- Linux裝置驅動程式設計之阻塞與非阻塞(轉)Linux程式設計
- 《JAVA併發程式設計實戰》原子變數和非阻塞同步機制Java程式設計變數
- 網路IO之阻塞、非阻塞、同步、非同步總結非同步
- 一直讓 PHP 程式設計師懵逼的同步阻塞非同步非阻塞,終於搞明白了PHP程式設計師非同步
- linux非阻塞式socket程式設計之select()用法Linux程式設計
- IO模式設定網路程式設計常見問題總結—IO模式設定,阻塞與非阻塞模式程式設計
- 同步非同步,阻塞非阻塞非同步
- 非同步、同步、阻塞、非阻塞非同步
- 同步、非同步、阻塞、非阻塞非同步
- 程式設計師OR非程式設計師,有些程式設計的事需要知道程式設計師
- 【網路程式設計】阻塞IO程式設計的坑程式設計
- 同步非同步 與 阻塞非阻塞非同步
- 理解阻塞、非阻塞、同步、非同步非同步
- 同步、非同步,阻塞、非阻塞理解非同步
- 同步、非同步、阻塞與非阻塞非同步
- 同步、非同步、阻塞和非阻塞非同步
- 美女程式設計師觀點:程式設計師最重要的非程式設計技巧程式設計師
- 併發程式設計之臨界區\阻塞\非阻塞\死鎖\飢餓\活鎖程式設計
- 程式執行緒、同步非同步、阻塞非阻塞、併發並行執行緒非同步並行
- 聊聊執行緒與程式 & 阻塞與非阻塞 & 同步與非同步執行緒非同步
- 併發-0-同步/非同步/阻塞/非阻塞/程式/執行緒非同步執行緒
- 程式設計師與非程式設計師的思維差異程式設計師
- [轉]阻塞/非阻塞與同步/非同步非同步
- 同步與非同步 阻塞與非阻塞非同步
- 10個理由,非程式設計師不嫁!程式設計師