俗话说"光说不练假把式",上一篇文里都只是光看着别人的源码说,貌似有点纸上谈兵的意思.
因此此次写一个简单的,本身定义协议的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
真强大,协程好厉害!!),而且是单进程的编程,不须要考虑锁,写起来就更轻松了.
最后附上程序效果图异步
这只是个吃饱撑着的程序,一点实际做用都没啊(好想被拍死!).吃饱撑着的缘由是我还没下决心去找工做...工做太难找啦(哭~~)!!!!好想被带走.................函数