俗話說"光說不練假把式",上一篇文裏都只是光看着別人的源碼說,貌似有點紙上談兵的意思.
因此此次寫一個簡單的,本身定義協議的server
.
既能夠熟悉Future和coroutine
的用法,又能夠在去除了複雜的http協議後,瞭解tornado
的工做原理.
代碼很少,加上空行和import也就200行不到.
在github上的源碼點這裏ios
websock
)tornado
的框架模式開發這個server
框架,讓用戶代碼開發方便,而且支持coroutine
telnet
handler
名稱,第二次通訊的內容是該handler
的方法名close
,需等待此鏈接全部的異步操做完成後才關閉鏈接由於想讓代碼儘可能少,因此委託模式沒有嚴格按照設計模式的規範寫,直接忽略掉了interface
的定義.嚴格來講是須要定義interface
和判斷傳入參數的類型的(泛華)
這是類的實例關係圖(也不知道是否是這樣畫...)git
MyServer和MyApplication的實例常駐.一個鏈接進來後就會建立圖中其餘的實例各一個.
github
1.爲了達到目標中的第一點,須要一個while循環,讀取了客戶端數據後,執行handler
,
當即繼續讀取下一條客戶端數據.直到客戶端關閉操做,引起StreamClosedError
才退出循環web
2.爲了達到目標中的第二點,判斷handler的返回值,若是類型是Future則yield處理,由於本方法有@gen.coroutine
,因此yield
就表明異步操做是在gen.Runner
中執行的.編程
3.爲了達到目標中的第三點,須要記錄每個異步操做,而且異步操做完成後移除.當客戶端主動關閉鏈接時,需判斷是否還有future
未完成.因此close代碼中給每一個future
加上done_callback
,用以檢查關閉設計模式
詳情見代碼 MyServerConnection._server_request_loopapp
@gen.coroutine def _server_request_loop(self, delegate): try: #get request adepter request_delegate = delegate.on_request(self) while True: try: message_future = self.stream.read_until_regex(b"\n\r?") message = yield message_future message = self._parse_data(message) except (iostream.StreamClosedError, iostream.UnsatisfiableReadError): app_log.error(' close the connect') self.close() return except Exception: gen_log.error("Uncaught exception", exc_info=True) self.close() return ret = request_delegate.on_message(message) #若是是異步執行的方法,保存future,用於確保close時,全部future都已完成 if isinstance(ret, Future): ret.add_done_callback(lambda f:self._serving_futures.remove(f)) self._serving_futures.append(ret) finally: delegate.on_close(self)
def close(self): def mayby_close(f): futures = self._serving_futures+self._pending_writes app_log.error(futures) if not any(futures): self.stream.close() pending_futrues = self._serving_futures+self._pending_writes if any(pending_futrues): map(lambda f:f.add_done_callback(mayby_close),pending_futrues) else: self.stream.close()
其實用@coroutine
的時候只須要記住幾點就好了
* 1.被包裝的函數(方法),返回值是Future
,
* 2.被包裝的函數走完最後一行代碼後,返回的Future
的callback
就會被運行(由於在Runner
中引起了StopIteration
錯誤,被set_result
了)
* 3.被包裝的函數是在gen.Runner
中運行的,而Runner
是在ioloop
(callback那塊)中運行的框架
代碼很是簡單,由於tornado
爲咱們提供了異步的庫(tornado
真強大,協程好厲害!!),而且是單進程的編程,不須要考慮鎖,寫起來就更輕鬆了.
最後附上程序效果圖異步
這只是個吃飽撐着的程序,一點實際做用都沒啊(好想被拍死!).吃飽撐着的緣由是我還沒下決心去找工做...工做太難找啦(哭~~)!!!!好想被帶走.................函數