到现在断断续续学习python也将近半个月了,总觉得书本(《Python基础教程.第二版》)上的项目有些过于理想化,可以用来巩固书本前面章节的语法知识(而我基本没怎么看前面的语法~),了解python的一些标准库,就是过于单调。
好在开源的python的项目众多,而且搭建学习环境简单迅速。
考虑到那些大而且知名的项目往往经过高度的发展,过多的版本迭代,封装、抽象的过于复杂,了解其整个的架构设计,类层次结构,调用栈都不是短期之功,与我快速学习python的目的不符,所以最终定下来web.py这个半学术型的项目,该项目短小精悍,又符合我服务器开发的职业身份,适合现在的我阅读,而且了解这个后,我今后用其写点小东西也方便快捷。
0.web.py介绍
web.py是一款轻量级的Python web开发框架,简单、高效、学习成本低,代码量少,以至于特别适合作为python web开发的入门框架。
官方站点:http://webpy.org/
1. 框架代码结构
我学习的对象是webpy-webpy-0.38版本,其大致目录结构如下(仅保留必要的源码部分):
webpy-webpy-0.38
│ code.py
├─docs
├─experimental
├─templates
│ index.html
├─test
├─tools
└─web
│ application.py
│ browser.py
│ db.py
│ debugerror.py
│ form.py
│ http.py
│ httpserver.py
│ net.py
│ python23.py
│ session.py
│ template.py
│ test.py
│ tree.txt
│ utils.py
│ webapi.py
│ webopenid.py
│ wsgi.py
│ __init__.py
├─contrib
└─wsgiserver
ssl_builtin.py
ssl_pyopenssl.py
__init__.py
对于不关心框架源码的开发者而言,其需要关注的是根目录下的app入口code.py文件以及templates文件夹下的的网页模板文件。
而本文,关注的是web.py框架源码主要集中的web文件夹,文件不多,但其中有我需要学习的很多东西。几个需要关注的文件:
- application.py 实现开发者的应用启动,应用响应最终的回调处理
- db.py 数据库的简单封装,根据应用开发的需求,可用可不用,上层业务使用
- form.py 表单处理,上层业务使用
- session.py cookies机制搞得session管理吧,上层业务使用
- template.py 网页模板的实现,上层业务使用
- httpserver.py 顾名思义了,http服务器,但看源码,并不具体实现监听和处理请求,根据不同需求可定制不同处理模式。
- wsgi.py 几种不同的符合wsgi规范的服务器运行模式
- webapi.py wsgi规范接口的一些包装
- wsgiserver 该文件夹下为独立程序运行的http服务器实现,整个框架的最底层,端口监听,http请求处理的实现
2. 数据处理流程
先看看web.py框架从接受客户端请求到返回这个机制的流程:
+---------------------------------+
| |
| application |
| |
+---------------------------------+
| |
| WSGIGateway(Gateway) |
| |
+---------------------------------+
| |
| CherryPyWSGIServer(HTTPServer) |
| |
+-----------+--------+------------+
^ |
| |
| |
| v
+------+--------+-------+
| |
| client or browser |
| |
+-----------------------+
3. 具体代码分析
那么,跟着上图的这个流程,咱们来看看代码:
CherryPyWSGIServer继承自HTTPServer,他的主要工作是初始化了http请求的requests线程池,确定最终响应的app,然后确定网关和监听地址,之后socket设置、端口绑定、监听都继承自父类处理。
|
|
httpserver中初始化的线程池ThreadPool内含有一个线程安全消息队列,由Queue.Queue()构造,而ThreadPool内的线程都为WorkerThread。该队列内缓存那些刚到的http连接对象,然后由数个WorkerThread线程持续不断的去消息队列中取出http连接对象来处理。
|
|
这便是之前放进队列中的http连接对象,省去了其他部分,主要看communicate()函数,HTTPConnection对象被RequestHandlerClass转换成HTTPRequest对象之后,解析req.parse_request(),最后响应req.respond()。
至于解析,http协议本身都是文本,熟悉服务器开发的应该都了解,不明白网上也有很多资料,这里就不展开说明解析函数了。
看看HTTPRequest对象的响应函数:
呵呵,看着一大串,其实也就一行self.server.gateway(self).respond(),就是说响应交给网关WSGIGateway(Gateway)处理了,也就是上图中第二层了。呼,终于往上走了一层!
最早CherryPyWSGIServer(HTTPServer)初始化时self.gateway = wsgi_gateways[self.wsgi_version]来初始化的网关,看wsgi_gateways字典,发现WSGIGateway_10是真正使用的网关,而WSGIGateway_10继承WSGIGateway类,只实现get_environ方法而已,也就是真响应在这里:
这里最终交给了早已初始化好的APP处理,wsgi_app(self.env, self.start_response),
交给app后WSGIGateway(Gateway)层接受请求部分完成,
application层根据具体业务逻辑,路由指定web页处理,然后返回出response对象,
WSGIGateway(Gateway)将response对象写入预先保持的HTTPRequest对象持有由socket构造的可写二进制文件描述符中。
至此,一次客户端http请求的过程完全结束!
4. 总结
web.py的这种3层的设计,我从上到下姑且称为应用层、代理层、网络层(注:这里并不对应OSI网络模型)。
这种设计很好的隔离了业务逻辑和网络通信底层,上层应用的开发,完全无需理会底层的变动,根据文档说明,web.py可以很容易的切换到第三方http服务器(如Apache)处理网络底层。
这一切都源于代理层的网关将底层实现隔离,切换只需要更改更改HTTPServer的gateway属性而已。
版权声明:
本文由greedcoder创作、发表并维护,
采用自由分享-保留署名-非商用-禁止演绎4.0(CC BY-NC-ND 4.0)国际许可协议进行许可.
版权有一点,侵权不一定究!
本文永久链接:https://greedcoder.github.io/2016/09/04/webpy-source-analysis/