文档章节

实践,用tornado实现自定义协议server

国夫君
 国夫君
发布于 2015/07/31 04:08
字数 963
阅读 372
收藏 17

##前言 俗话说"光说不练假把式",上一篇文里都只是光看着别人的源码说,貌似有点纸上谈兵的意思. 所以这次写一个简单的,自己定义协议的server. 既可以熟悉Future和coroutine的用法,又可以在去除了复杂的http协议后,了解tornado的工作原理. 代码不多,加上空行和import也就200行不到. 附上源码地址 ##目标

  • 1.定义一个简单的协议,达到远程调用的效果,并且是个长连接的协议(类似websock)
  • 2.模仿tornado的框架模式开发这个server框架,让用户代码开发方便,并且支持coroutine
  • 3.为了省去客户端的开发,客户端使用telnet

##协议

  • 1.客户端连接成后,以换行符分割每次通信内容
  • 2.第一次通信内容是需要执行handler名称,第二次通信的内容是该handler的方法名
  • 3.对于客户端的主动close,需等待此连接所有的异步操作完成后才关闭连接 最后运行方式如下图:

输入图片说明

##源码说明 ###总览 因为想让代码尽量少,所以委托模式没有严格按照设计模式的规范写,直接忽略掉了interface的定义.严格来说是需要定义interface和判断传入参数的类型的(泛华) 这是类的实例关系图(也不知道是不是这样画...)

输入图片说明

MyServer和MyApplication的实例常驻.一个连接进来后就会创建图中其他的实例各一个.

###异步说明

  • 1.为了达到目标中的第一点,需要一个while循环,读取了客户端数据后,执行handler, 立即继续读取下一条客户端数据.直到客户端关闭操作,引发StreamClosedError才退出循环

  • 2.为了达到目标中的第二点,判断handler的返回值,如果类型是Future则yield处理,因为本方法有@gen.coroutine,所以yield就代表异步操作是在gen.Runner中执行的.

  • 3.为了达到目标中的第三点,需要记录每一个异步操作,并且异步操作完成后移除.当客户端主动关闭连接时,需判断是否还有future未完成.所以close代码中给每个future加上done_callback,用以检查关闭

详情见代码 MyServerConnection._server_request_loop

@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 其实用@coroutine的时候只需要记住几点就行了

  • 1.被包装的函数(方法),返回值是Future,
  • 2.被包装的函数走完最后一行代码后,返回的Futurecallback就会被运行(因为在Runner中引发了StopIteration错误,被set_result了)
  • 3.被包装的函数是在gen.Runner中运行的,而Runner是在ioloop(callback那块)中运行的

###总结 代码非常简单,因为tornado为我们提供了异步的库(tornado真强大,协程好厉害!!),并且是单进程的编程,不需要考虑锁,写起来就更轻松了. 最后附上程序效果图 ![效果][1]

输入图片说明

##废话 这只是个吃饱撑着的程序,一点实际作用都没啊(好想被拍死!).吃饱撑着的原因是我还没下决心去找工作...工作太难找啦(哭~~)!!!!好想被带走.................

© 著作权归作者所有

国夫君
粉丝 7
博文 5
码字总数 7443
作品 0
惠州
私信 提问
tronado 源码框架分析

一. Tornado是什么? Facebook发布了开源网络服务器框架Tornado,该平台基于Facebook刚刚收购的社交聚合网站FriendFeed的实时信息服务开发而来.Tornado由Python编写,是一款轻量级的Web服务器...

颓废的幻想者
2013/10/30
223
0
Python Web部署方式总结

学过PHP的都了解,php的正式环境部署非常简单,改几个文件就OK,用FastCgi方式也是分分钟的事情。相比起来,Python在web应用上的部署就繁杂的多,主要是工具繁多,主流服务器支持不足,在了解...

Yamazaki
2015/11/16
229
0
openstack-webservice之eventlet

tornado是一个完整的轻量级web框架,利用tornado即可完成一个网站的搭建,而openstack的web架构却采用另一种思路来设计。这个设计思路我之前提到过,也就是openstack的所有设计,都是插件式,...

Jun_Wong
2017/11/20
0
0
Tornoda使用相关

本文档意在帮助Tornado初学者快速搭建Tornado环境,安装所需的依赖包。由于Unix版本众多,所以文档中的安装方法不可能适用于所有系统,仅供参考,谢谢。 版本要求 Python-2.6.9 (< 3.X) to...

boatgm
2015/04/24
2
0
你真的了解WebSocket吗?

老男孩IT教育alex python教学总监教你认识WebSocket WebSocket协议是基于TCP的一种新的协议。WebSocket最初在HTML5规范中被引用为TCP连接,作为基于TCP的套接字API的占位符。它实现了浏览器与...

python入门
2017/05/25
0
0

没有更多内容

加载失败,请刷新页面

加载更多

Echars鼠标点击事件多次触发

本文转载于:专业的前端网站➭Echars鼠标点击事件多次触发 gChart.on('click', function (params) { if (params.componentSubType == "bar" && params.componentType == "serie......

前端老手
11分钟前
2
0
springboot2.0.6(附) 解析META-INF/spring.factories通过系统加载类获取对应的 class 的全限定名称

在 SpringBoot中是通过getSpringFactoriesInstances(Class<T> type)方法获取所有classpath下面的META-INF/spring.factories文件,然后根据type值找到对应的 class 的全限定名称列表。下面我来...

小亮89
13分钟前
2
0
zk工厂方法实现NIOServerCnxnFactory

NIOServerCnxnFactory类 内部类 AbstractSelectThread AcceptThread SelectorThread 属性 ZOOKEEPER_NIO_SESSIONLESS_CNXN_TIMEOUT 10s session过期时间 ZOOKEEPER_NIO_NUM_SELECTOR_THREADS......

writeademo
16分钟前
2
0
天猫精灵业务如何使用机器学习PAI进行模型推理优化

作者:如切,悟双,楚哲,晓祥,旭林 引言 天猫精灵(TmallGenie)是阿里巴巴人工智能实验室(Alibaba A.I.Labs)于2017年7月5日发布的AI智能语音终端设备。天猫精灵目前是全球销量第三、中国...

阿里云官方博客
24分钟前
3
0
BJL技巧之大路馆擦法—《利辰逸》

很多朋友刚玩百佳时间不长,不知道如何看路,今 天我就来简单的讲下看大路的方法。 都是前辈教的,这里我只是简单复述一下。 大路的观察方法有以下几种: 先从庄闲的数量变化说起。 庄闲的强...

那女孩对我说
24分钟前
2
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部