开始Tornado的源码分析之旅
2018-01-08 17:58
246 查看
Tornado 是由 Facebook 开源的一个服务器“套装”,适合于做 python 的 web 或者使用其本身提供的可扩展的功能,完成了不完整的 wsgi 协议,可用于做快速的 web 开发,封装了 epoll 性能较好。文章主要以分析 tornado 的网络部分即异步事件处理与上层的 IOstream 类提供的异步IO,其他的模块如 web 的 tornado.web 以后慢慢留作分析。
下面开始我们的 Tornado 之旅,看源代码之前必定需要有一份源码了,大家可以去官网下载一份。这里分析的是
3.1.1。
Tornado 的源码组织如下:
tornado网络部分最核心的两个模块就是ioloop.py与iostream.py,我们主要分析的就是这两个部分。
ioloop.py 主要的是将底层的epoll或者说是其他的IO多路复用封装作异步事件来处理。
iostream.py主要是对于下层的异步事件的进一步封装,为其封装了更上一层的buffer(IO)事件。
我们先来看看 ioloop(文档地址:http://www.tornadoweb.org/en/stable/ioloop.html):
We use epoll (Linux) or kqueue (BSD and Mac OS X) if they are available, or else we fall back on select(). If you are implementing a system that needs to handle thousands of simultaneous connections, you should use a system that supports either epoll or kqueue.
Example usage for a simple TCP server:
可以看到在注释前都是使用了传统的创建服务器的方式,不用多介绍,注意就是把套接口设置为非阻塞方式。
创建ioloop实例,这里是使用了ioloop.IOLoop中的 instance()静态方法,以 @classmethod 方式包装。
在后面的add_handler中,程序为我们的监听套接口注册了一个回调函数和一个事件类型。工作方式是这样,在注册了相应的事件类型和回调函数以后,程序开始启动,如果在相应的套接口上有事件发生(注册的事件类型)那么调用相应的回调函数。
当监听套接口有可读事件发生,意味着来了一个新连接,在回调函数中就可以对这个套接口accept,并调用相应的处理函数,其实应该是处理函数也设置为异步的,将相应的连接套接口也加入到事件循环并注册相应的回调函数,只是这里没有展示出来。
在使用非阻塞方式的accept时候常常返回EAGAIN,EWOULDBLOCK 错误,这里采取的方式是放弃这个连接。
鸟瞰Tornado框架的设计模型
在深入到模块进行分析之前,首先来看看Tornado的设计模型。
Tornado框架设计模型
从上面的图可以看出,Tornado 不仅仅是一个WEB框架,它还完整地实现了HTTP服务器和客户端,在此基础上提供WEB服务。它可以分为四层:
最底层的EVENT层处理IO事件;
TCP层实现了TCP服务器,负责数据传输;
HTTP/HTTPS层基于HTTP协议实现了HTTP服务器和客户端;
最上层为WEB框架,包含了处理器、模板、数据库连接、认证、本地化等等WEB框架需要具备的功能。
理解Tornado的核心框架之后,就能便于我们后续的理解。
代码文件级别的设计组成,请阅读 为什么要阅读Tornado的源码? 。
下面开始我们的 Tornado 之旅,看源代码之前必定需要有一份源码了,大家可以去官网下载一份。这里分析的是
3.1.1。
Tornado 的源码组织如下:
tornado网络部分最核心的两个模块就是ioloop.py与iostream.py,我们主要分析的就是这两个部分。
ioloop.py 主要的是将底层的epoll或者说是其他的IO多路复用封装作异步事件来处理。
iostream.py主要是对于下层的异步事件的进一步封装,为其封装了更上一层的buffer(IO)事件。
我们先来看看 ioloop(文档地址:http://www.tornadoweb.org/en/stable/ioloop.html):
We use epoll (Linux) or kqueue (BSD and Mac OS X) if they are available, or else we fall back on select(). If you are implementing a system that needs to handle thousands of simultaneous connections, you should use a system that supports either epoll or kqueue.
Example usage for a simple TCP server:
01 | import errno |
02 | import functools |
03 | import ioloop |
04 | import socket |
05 |
06 | def connection_ready(sock, fd, events): |
07 | while True : |
08 | try : |
09 | connection, address = sock.accept() |
10 | except socket.error, e: |
11 | if e.args[ 0 ] not in (errno.EWOULDBLOCK, errno.EAGAIN): |
12 | raise |
13 | return |
14 | connection.setblocking( 0 ) |
15 | handle_connection(connection, address) |
16 |
17 | sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0 ) |
18 | sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1 ) |
19 | sock.setblocking( 0 ) |
20 | sock.bind(("", port)) |
21 | sock.listen( 128 ) |
22 |
23 | # 创建一个ioloop 实例 |
24 | io_loop = ioloop.IOLoop.instance() |
25 | # connection_ready 的第一个参数为 sock,即 socket 的返回值 |
26 | callback = functools.partial(connection_ready, sock) |
27 | # 注册函数,第一个参数是将 sock 转换为标准的描述符,第二个为回调函数,第三个是事件类型 |
28 | io_loop.add_handler(sock.fileno(), callback, io_loop.READ) |
29 | io_loop.start() |
创建ioloop实例,这里是使用了ioloop.IOLoop中的 instance()静态方法,以 @classmethod 方式包装。
在后面的add_handler中,程序为我们的监听套接口注册了一个回调函数和一个事件类型。工作方式是这样,在注册了相应的事件类型和回调函数以后,程序开始启动,如果在相应的套接口上有事件发生(注册的事件类型)那么调用相应的回调函数。
当监听套接口有可读事件发生,意味着来了一个新连接,在回调函数中就可以对这个套接口accept,并调用相应的处理函数,其实应该是处理函数也设置为异步的,将相应的连接套接口也加入到事件循环并注册相应的回调函数,只是这里没有展示出来。
在使用非阻塞方式的accept时候常常返回EAGAIN,EWOULDBLOCK 错误,这里采取的方式是放弃这个连接。
鸟瞰Tornado框架的设计模型
在深入到模块进行分析之前,首先来看看Tornado的设计模型。
Tornado框架设计模型
从上面的图可以看出,Tornado 不仅仅是一个WEB框架,它还完整地实现了HTTP服务器和客户端,在此基础上提供WEB服务。它可以分为四层:
最底层的EVENT层处理IO事件;
TCP层实现了TCP服务器,负责数据传输;
HTTP/HTTPS层基于HTTP协议实现了HTTP服务器和客户端;
最上层为WEB框架,包含了处理器、模板、数据库连接、认证、本地化等等WEB框架需要具备的功能。
理解Tornado的核心框架之后,就能便于我们后续的理解。
代码文件级别的设计组成,请阅读 为什么要阅读Tornado的源码? 。
相关文章推荐
- 2.开始Tornado的源码分析之旅
- 开始Tornado的源码分析之旅
- MiniGUI源码分析-- 开始篇
- Tornado源码分析之http服务器篇
- tornado 源码分析 之 异步io的实现方式
- tornado框架源码分析---Application类之debug参数
- tornado源码分析-多进程
- MySQL源码分析及核心内幕之4 -- 源码服务端main函数开始及启动流程
- Nouveau源码分析(一):从module_init开始
- Tornado源码分析之HTTP服务请求解析
- yii2 源码分析1从入口开始
- Nouveau源码分析(一):从module_init开始
- Tornado源码分析 --- 静态文件处理模块
- 决定从头开始分析u-boot-1.1.4源码(三)
- Libevent源码分析—从使用Libevent库开始
- Tornado源码分析之http服务器篇
- tornado源码分析
- spring源码分析,重新认识spring四(回顾下上篇的问题,以及从spring 的常用模式开始)
- tornado源码分析系列 [网络层 IOLoop类] 优秀系列文章可以看看
- spring-boot源码分析(1)--从main方法开始