[Karrigell]Karrigell网络框架结构分析

上传人:tia****nde 文档编号:36845259 上传时间:2018-04-03 格式:DOC 页数:9 大小:45.50KB
返回 下载 相关 举报
[Karrigell]Karrigell网络框架结构分析_第1页
第1页 / 共9页
[Karrigell]Karrigell网络框架结构分析_第2页
第2页 / 共9页
[Karrigell]Karrigell网络框架结构分析_第3页
第3页 / 共9页
[Karrigell]Karrigell网络框架结构分析_第4页
第4页 / 共9页
[Karrigell]Karrigell网络框架结构分析_第5页
第5页 / 共9页
点击查看更多>>
资源描述

《[Karrigell]Karrigell网络框架结构分析》由会员分享,可在线阅读,更多相关《[Karrigell]Karrigell网络框架结构分析(9页珍藏版)》请在金锄头文库上搜索。

1、Karrigell 网络框架结构分析网络框架结构分析 我喜欢有灵气的程序作品,喜欢看 tvb 电视剧,趁着欣赏 tvb 的布衣神相的同时,我决定分析一下 Karrigell 的框架代码,看看它是怎么实现的,也作为写 zope 结构分析过程中的一个插曲_。我还是喜好从一个框架的启动开始,一直跟踪它的工作流程,从而分析它各种功能的协作与实现。Karrigell 使用的是一个异步模型,但是它不是直接使用 asyncore 和 asynchar 标准模块,原作者说是为了使处理的逻辑简单一点,但是 Server 的算法和 asyncore 的算法是一样的。(可以看看我的 zope 的结构分析中的 med

2、usa 篇)。Karrigell 的 server其实非常简单就是 soocket-bind-listen-accept-new client 甚至可以说它只是一个通用的 server,而不是 httpserver(不过每一个 server,在最地层都是这个样子的啦,其实我想说的是,在接受连接这一步上,Karrigell 使用的是自己的手工代码,而不是现有的 http server 库。(zope 使用的是 medusa)在接收到新的请求(accept 成功后,KG 创建一个 asyncRequestHandler 实例与它对应,并把它加入到监听队列中,这个队列是一个字典)。也就是说所有的是与

3、协议相关的事情和响应的流程都是通过这个 asyncRequestHandler(继承 DialogManager和 KarrigellRequestHandler)来实现的,与 asyncore 的设计一样,当 server 监听到对应的请求有数据到达时,或者可以发送数据时,就会调用 DialogManager 的handle_read 和 hande_write,从而实现数据处理。先看 handle_read,也许是类似的东西看多了,KG 在完成的工作我们可以猜到:首先是收集输入的数据,然后就是解析头部,一般来说头部都只要解析到/r/n/r/n就可以了,因为 python 的标准模块 cgi

4、.FieldStorage 会帮我们把 POST 或者是 PUT 的数据以树的结构解析出来(cgi.FieldStorage 具体的处理流程可以看看我前面写的 cherrpy3结构分析)。当然还要加上基本的错误处理,否则 KG 就会很脆弱了。看看原代码,的确和我想象的差不多,不过这里 KG 做了完整头部的缓冲。这里有一个 parse_request 的调用这个函数是来自于 BaseHTTPRequestHandler 中的,正如KG 所说的,其实它自己并不解析 HTTP 协议,所有的东西都是借助 python 的标准模块 SimpleHTTPServr 或相关的功能模块完成。所以在本分析只对于

5、这些标准模块的结合的细节上说明,至于 SimpleHTTPServer 的工作方式,留在分析SimpleHTTPServer 的时候再展开。由于在初始化的过程中 DialogManager 并没有调用基类的_init_,所以DialogManager 必须实现一些标准模块中需要的调用接口,那个 wfile 就是为了要实现这样的协作接口而引入的,同时一些也要覆盖一些基本的成员函数,例如;do_GET等。这里有一点需要注意的,对于 POST 方式提交的数据,KG 做了一件非常傻的事,就是自己先缓冲提交的数据(包括:把过大的上传信息保存为临时文件,然后又通过cgi.FieldStorage 来重新组

6、织这些数据,在 KG 的设计中这是没有办法避免的,因为KG 的设计是基于复用 IO,这种模式的最大的特点(也可以说是优点/局限)就是单线程,任何的数据交互都不能阻塞,否则导致整个系统阻塞)。所以为了不阻塞,KG 必须在数据完成接收完前(可以调用 cgi.FieldStorage 进一布分析上传的数据前)进行自己缓存,而为了节省内存,它又不可避免地创建临时文件。在处理完 Client 提交地数据以后,KG 很简单地根据请求地命令调用(do_XXX/GET/HEAD/POST),其实这些调用最后都会转到 self.pre_handle_data()在整个函数中做了一个很奇怪地操作,那就是将 sel

7、f.wfile 清空,到这里为止,我不能想象这个操作到底有什么含义(在后面的分析中我们可以看到它的作用)?这个 self.wfile只有在 parse_request 调用时用于产生(保存出错的信息,但是这里却把它清空了?难道这是为了表示一个结束?还是在后面进行的处理需要重写这个 self.wfile?现在先不管),接着就是调用 self.handle_data()这个 self.handle_data()做的一件事就是寻路,也就是根据前面 parse_request 的结果得到对应的文件,这个只是用户请求的文件,不一定是真实存在的,同时translate_path 函数还有转化别名(alia

8、s)路径的功能,但是从它的转换算法来看,alias 路径是通过路径分析中一个名称映射的,比如:http:/localhost/alise1/file1.pyhttp:/localhost/alise2/file2.py这里的分割顺序是固定的,也就是说必须在 base 的后面第一个分割路径是一个定义好的 alias 路径alias: doc: documentation。路径解析完后进行的是文件类型检测,如发现是一个文件夹,那么尝试寻找index.html 和 index.htm,这里并没有文档上说的还会寻找 index.ks、index.pih 等(看到这里的时候我还没有看 Karrigell

9、RequestHandler 对于 handle_data 的覆盖_),当发现对应的文件后,那么根据文件的后缀名猜测文件的类型,接着就是将请求的文件内容封装为一个 self.sources 数组里(当然这种处理的过程中,会先检查对应的数据长度,对于过长的文件长度,会独立成一个 wfile 对象,而对于比较小的内容,就会直接保存在 self.wfile 中),可以看到,这里使用了一个技巧:首先使 self.wfile 对象总是指向 self.sources 的最后一个元素,同时在调用 self.finish的时候会将一个 None 对象直接加入到 self.source 中,并把 writeab

10、le 调用变成 true,这样就能够在 handle_write 的时候进行统一的对 self.sources 进行操作,不过在这里留了一个很大的问号到底动态操作是怎么解析-执行-返回的呢?(这些是在KarrigellRequestHandler 覆盖的 handle_data 中处理的)带着这个问题,我们继续看 handle_write 的实现:晕,这个函数只是非常标准的socket.send 的 wrapper,一点动态的迹象都没有,看来这个 DialogManager 是处理动态资源的,看来我只能把目光放到一个从名字上就能知道它是 KG 非常重要的组成部分的一个模块(KarrigellR

11、equestHandler)上,打开这个文件,我非常高兴发现了handle_data,因为根据 mro 规则,python 解析器首先会找到这个处理函数,从而覆盖了 DialogManager.handle_data 函数。不用多说了,一切的动态功能就是在这里发生的。其实我写关于 Karrigell 的分析,最想看的就是它的模板机制。顺便说一下,KarrigellRequestHandler 除了覆盖了 handle_data 函数外,还覆盖了send_error 函数,同时从这些代码痕迹也可以看到 KG 的作者开发这个框架的时候最先就是实现了静态文件的处理,然后才一步一步地吧动态功能(模板功

12、能)加入到 KG中的,我想完成这个静态的功能最最主要的目的就是熟悉 HTTP 协议。现在我们一起看看 KarrigellRequestHandler 这个模块是怎么工作的:首先 KarrigellRequestHandler 继承 LocalizedRequestHandler,而LocalizedRequestHandler 并没有做很多事情,从它的名字我们可以知道这个模块主要负责语言的转换的,它是出于友好(扩展),我们先分析 KarrigellRequestHandler 的handle_data 的工作。在 KarrigellRequestHandler 中的 handle_data 实

13、际上是一个 wrapper,它内部调用try_handle_data 函数,这个才是真正负责动态脚本的加载与运行。try_handle_data函数比较长,但是结合 KG 的使用说明,我们很容易可以知道作者的思路(我总喜欢yy 作者的想法):首先应该是路径分析(任何 HTTPserver 都会做的事情),然后是按照“htm, html, py, pih, hip, ks“的顺序搜索用户请求的文件(又或者是追加用户可能的请求文件,KG 有一个很奇怪的规则,就是这些文件的优先级其实是并列的,也就是说,如果用户不明确指定想要访问的文件,那么,如果存在两个可以响应用户请求的文件,那么 KG 就会抛出异

14、常),然后就是获得这些文件的内容,然后进行解析,最后把解析(运行)的结果返回给用户。有了上面的主体流程的概念,我们在看看源代码是不是这样的,爽,基本差不多了,但是 KG 做了更多的东西:分析路径-虚拟路径的映射-提取路径中的子信息(也就是对于 ks 文件而言,如果存在多个响应函数,那么在 subpath 中可以指定)。在cherrpypy3 中的寻路算法是根据树型对象的属性(expose=True)的方式最后得到响应的函数的,而 KG 中没有这种树型的对象结构,它使用的是文件平行划分,关于cherrypy3 的分析请看我的另一篇分析。KG 做的事情还包括;隐藏路径检查、隐藏文件扩展名的检查,这

15、些都不是我最感兴趣的(因为这些都是很常用的代码,灵气相对较小),我最感兴趣的是它的 cache 算法和模板解析过程。好,我们先来看看模板的工作过程(其实 KG 的方便和灵气很大程度上取决于这一特色功能上):首先引起我注意的是 Template.getScript(),顾名思义,这个函数肯定是装载对应的脚本模块,从源代码可以看到,它只是简单地使用 sys.modules 来装载指定的解析模块,而这些模块的import是发生在 import Template 的时候,结合k_config.handle_extensions 来得到相应的模块的导入。当然这个模块是 KG 开发的(从它的算法可以看到,

16、用这种模式,可以支持很多中类型扩展,甚至于可以支持其他的脚本语言,莫非 KG 想大小通吃?),每一个解析模块可以近似理解为 apache中一个 mod_*.so(KG 连命名也抄袭了。),这种解析模块是有命名规则的,它必须包含一个命名为 Script 的可调用对象,因为源代码就是这么写的。好,看来这个Script 就是负责解析的工作的。我选了 mod_hip.py 看了一下,很简单,就是一个手工把单纯是字符串的行(string)转换为 python 的语言print string的样子,不过这里它使用了 tokenize 模块,也就是说,在 python 解析之前先手工替换一些源代码,然后把结果通过 StringIO 保存起来,以后作为 python 的源码编译,然后再运行。就这么简单。需要注意的是,python 的运行所需要的环境变量的传递是怎么进行的呢,在 Template 这个文件中给出了答案,它建了一个方便运行脚本的 wrapper-ExecContext 类,这个类主要做两件事情:1、初始化名空间,也

展开阅读全文
相关资源
相关搜索

当前位置:首页 > 中学教育 > 试题/考题

电脑版 |金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号