Tornado-6.0.3源码分析之前述

闲言之语

许久没有想起写博客了,之前尝试写了几遍,但是都没有好好坚持下来。以致于,很多自己遇到的问题,自己想到的解决方案没有被记录下来。如今回想起来,竟也是几乎全忘光了,突然感觉这种状态不能这么继续下去。如今,在学习python的一个web框架库tornado,感觉自己应该需要不断整理输出自己的思路,记录自己的学习历程;对自己而言,也是一种学习方式,对他人而言,也是一种交流方式;本人使用的是tornado-6.0.3版本,属于比较新的版本。另外,本人是python菜鸟一枚,如果有大神路过,还望能指点一二,不胜感激。

一、相关知识点储备

要想理解学习Tornado的源码,至少需要学习了解python中类相关的操作,如类继承、类重载实现、元类等;还需要学习熟悉asyncio库的基本知识,比如event loop、future相关的知识点,这个是理解tornado底层网络异步实现的基础,因为Tornado 6.0.3版本使用的底层异步网络就是对asyncio库的一种重装包装;早期版本的tornado底层的异步网络是自己实现的,主要使用是epoll知识,这部分就不再多说了,想了解早期版本的话,可以网上搜索一下。这里还是以较新版本为例。

二、tornado整体框架简述

Tornado是一个python语言的web框架实现和异步网络通讯库。使用非阻塞式网络IO实现,可以同时支持成千上万的网络连接,适合于网络长连接,websocket通讯和其它需要长连接的应用。其官网文档说明链接是:https://www.tornadoweb.org/en/stable/
正常来说,Tornado库的相关模块功能可以划分为六大部分。
其一,web服务框架;主要是用于搭建实现web服务相关的功能;
其二,HTTP协议的客户端和服务端的实现,即完整的支持http协议功能;
其三,异步网络通讯实现,即实现非阻塞的网络传输;
其四,协程的相关实现库。
其五,其它服务实现的融合。如WSGI(Web Server Gateway Interface)的支持
其六,整个库其它公共的实现,如日志记录等

既然是要学习源码,那么下载一份源代码是必须的。
Tornado的源码文件如下所示:
在这里插入图片描述
对应于上述的分类,各模块的划分如下:

web框架相关

  • web.py 主要是包括了对请求处理类RequestHandler和应用路由查找类Application的定义
  • template.py 包含的是提供灵活的对外输出的模版实现
  • routing.py 是对路由查找的基本定义实现,上述的Application类就是对这里定义的相关路由类的继承与实现
  • escape.py 是对网络字符转码相关的实现
  • locale.py 是web页面进行国际化翻译的实现
  • websocket.py 是对于websocket通讯的支持

HTTP 客户端和服务端相关

  • httpserver.py 非阻塞式 HTTP 服务端的实现定义,这里是对服务端的逻辑实现定义。
  • httpclient.py 异步HTTP 客户端的实现定义,这里是对客户端的逻辑实现的基本定义,相当于接口定义。真正的相关实现是 simple_httpclient.py 模块和 curl_httpclient.py 模块。 其中simple_httpclient是Tornado默认使用的客户端实现,比较通用简单些,而curl_httpclient客户端是依赖于curl库,提供了一些simple_httpclient没有的特性功能
  • httputil.py 是包含一些HTTP相关的公共操作,比如HTTP 头域定义等
  • http1connection.py 是对HTTP 1.x协议的定义实现。

异步网络定义

  • ioloop.py 是对asyncio库的包装定义
  • iostream.py 是对socket连接的包装。
  • netutil.py 网络相关的公共操作实现
  • tcpclient.py 基于IOStream的tcp 客户端实现
  • tcpserver.py 基于IOStream的tcp 服务端实现

其它服务的融合

  • auth.py 鉴权相关
  • wsgi.py 与其它python web框架的对接实现
  • platform.caresresolver.py DNS解析相关的实现
  • platform.twisted.py 实现tornado与Twisted的桥接
  • platform.asyncio.py 实现tornado与asyncio的桥接

其它公共操作

  • autoreload.py 自动重载程序
  • concurrent.py 对asnyncio 的Future的处理操作
  • log.py 日志记录
  • options.py 命令行解析实现
  • testing.py unittest测试
  • util.py 普通的公共操作

在代码实现层面上,其框架设计类图如下所示。虽然不是每个相关类都体现出来了。但是整体来说,是没有太大差别的。(PS:后面再回来补充相关的整体类图说明)
此图来源自:http://www.nowamagic.net/academy/detail/13321014
在这里插入图片描述
可以看到,这是一个向上的层级服务实现。最底下的io event事件进行网络数据的读写,通过再次包装成IOStream类后,为TCP传输层服务,而Http协议建立在tcp之上,最上面的用户层是web应用层,涉及到web搭建的各个方面。

三、简单的例子

在学习介绍Tornado相关的例子前,先来看一下,一个普通的网络服务器的框架样子。

import socket

sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.setblocking(0)
sock.bind("", 8888)
sock.listen(128)

while True:
	try:
		connection, address = sock.accept()
		connection.sendall("hello world")
		connection.close()
	except BlockingIOError:
		return

这是一个典型的阻塞式的tcp服务端。所需要完成的步骤是:
1 创建一个socket实例,sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0)
2 设置该sock实例的参数,如端口可复用等,sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
3 绑定特定的本地端口和地址,sock.bind("", 8888)
4 设置最大监听缓冲长度,sock.listen(128)
5 等待客户端的连接,connection, address = sock.accept()
6 与该客户端进行数据交互处理,在这里只是由服务端发送了一个"hello world", connection.sendall(“hello world”)
7 处理结束,关闭该客户端,继续等待下一个客户端。connection.close()

这些步骤就是一个处理TCP连接的主要操作。而这个服务器的实现缺陷也是很明显的。比如,程序只能阻塞等待,而不能做其它事情,这就造成了资源浪费;对于数据的处理过程也是不具备可扩展性,如果要添加其它处理过程,就是修改到原来的代码等等;那么Tornado库,在网络处理方面就是优化实现了这些,把阻塞的等待变成了异步的网络监听,在监听到有新的连接时,再“激活处理”;下面先简单看下Tornado提供的简单例子。

import tornado.ioloop
import tornado.web

class MainHandler(tornado.web.RequestHandler):
	def get(self):
		self.write("hello, World")

if __name__ == "__main__":
	application = tornado.web.Application([
		(r"/", MainHandler),
	])
	application.listen(8888)
	tornado.ioloop.IOLoop.current().start()

在这个例子中,可以看到,主要完成的事情有:
1 实现一个数据处理相关的类,MainHandler,该类继承自tornado.web.RequestHandler类,并重载实现了get方法。tornado.web.RequestHandler这个类是Tornado提供出来的Web请求的处理基类,其子类只需要关注相应的方法重载即可实现对数据的操作。
2 实例化一个web应用路由application,该application的作用就是当有客户端,比如浏览器访问 http://127.0.0.1:8888 这个网址时,把该请求提交给MainHandler类的实例处理,类的实例化由application内部实现。
3 设置监听的端口地址。需要注意的是,这里的listen方法,不同于上面的例子中的sock.listen,在这个listen方法中,涉及到了上述的创建一个sock实例、设置sock相关参数、绑定相应的端口、设置监听长度、准备启动异步网络监听,等待客户端连接;这些所有操作。
4 启动io 事件循环tornado.ioloop.IOLoop.current().start()。这里启动后,步骤3中的异步监听实现才真正的运行起来。

从这个例子我们可以看到,在功能实现和操作方面,Tornado整体实现上就是简化了网络连接相关的操作,提供了方面的可拓展的web应用程序,而于如何创建网络连接、如何接收客户端数据、数据是如何提交出来给用户处理的等等,这些细节,对于库的使用者,是不必关心的。但是对于源码查看分析,这些才是关键。

四、总结

这篇里面,主要是初步接触Tornado库,基本了解一下Tornado。

  • Tornado 本身概要,它是一个web框架和异步网络库实现,适合长连接的应用场景。
  • Tornado 整体的基本分层情况
  • Tornado 简单使用例子,对比于典型的服务端程序的差别。

代码交流 2020