源码里的结构:
tornado
├── auth.py
├── autoreload.py
├── ca-certificates.crt
├── curl_httpclient.py
├── database.py
├── escape.py
├── gen.py
├── httpclient.py
├── httpserver.py
├── httputil.py
├── __init__.py
├── ioloop.py
├── iostream.py
├── locale.py
├── netutil.py
├── options.py
├── platform
│ ├── auto.py
│ ├── common.py
│ ├── __init__.py
│ ├── interface.py
│ ├── posix.py
│ ├── twisted.py
│ ├── windows.py
├── process.py
├── simple_httpclient.py
├── stack_context.py
├── template.py
│ ├── csv_translations
│ │ └── fr_FR.csv
│ ├── gettext_translations
│ │ └── fr_FR
│ │ └── LC_MESSAGES
│ ├── __init__.py
│ ├── README
│ ├── static
│ │ └── robots.txt
│ ├── templates
│ │ └── utf8.html
├── util.py
├── web.py
├── web.py~
├── websocket.py
├── wsgi.py
花了一些时间,准备看tornado的源码, 下午只看了部分http相关的, 结构理出来, google了部分资料, 然后自己理了理思维, 发现自己理解基本是对的, 在http://ispe54.blogspot.com/2013/04/tornado-1.html这篇文章理解下更加清晰了.
由简单的hello world程序开始, 看进去源码:
class MainHandler(tornado.web.RequestHandler): def get(self): return self.finish(‘hello world’)
\#初始化一个application类的实例
class Application(tornado.web.Application):
def __init__(self):
handlers.append((r'/', MainHandler))
tornado.web.Application.__init__(self, handlers, **config.web_config.settings)
self.session_manager = common.session.TornadoSessionManager(config.web_config.settings["session_secret"],
config.web_config.settings["session_dir"])
self.db = common.util.get_user_db()
….
def main():
http_server = tornado.httpserver.HTTPServer(Application(), xheaders=True)
http_server.listen(8888)
tornado.ioloop.IOLoop.instance().start()
</pre>
1, 先说Application类, 它和RequestHandler同时位于tornado.web模块内, 它总共没多少代码,
Application主要是初始化一些option.settings的参数, 将实例代码中的handlers加入到self.handlers中, 最后重写了__call__函数, 在后面将Application实例传给HTTPServer作为callback, HTTPServer内会有一系列的方法, 将会调用callback(), 实际就会运行这个__call__:
2, tornado.httpserver.HTTPServer 类只是提供一个基础httpserver的方法, httpserver.py和netutil.py 内的TCPServer,这两个文件主要是实现http协议,解析header 和 body, 生成request,回调给appliaction, 在httpserver.py内有一个HTTPConnection, 实现http协议的连接部分. 对于底层的socket, io缓冲等, 是由TCPServer中, 将ioloop, iostream关联在一起实现的.
源码里说HTTPServer类只是个简单的http协议实现:
A server is defined by a request callback that takes an HTTPRequest
instance as an argument and writes a valid HTTP response with
`HTTPRequest.write`. `HTTPRequest.finish` finishes the request (but does
not necessarily close the connection in the case of HTTP/1.1 keep-alive
requests). A simple example server that echoes back the URI you
requested::
def handle_request(request):
message = "You requested %s\n" % request.uri
request.write("HTTP/1.1 200 OK\r\nContent-Length: %d\r\n\r\n%s" % (
len(message), message))
request.finish()
http_server = httpserver.HTTPServer(handle_request)
HTTPServer是tornado.netutil.TCPServer的子类, HTTPServer在构造函数__init_里增加了一些属性, 然后重写了TCPServer的handle_stream:
def handle_stream(self, stream, address):
HTTPConnection(stream, address, self.request_callback,
self.no_keep_alive, self.xheaders)
handle_stream 这个方法, 会在TCPServer里被_handle_connection方法调用:
def handle_stream(self, stream, address):
"""Override to handle a new `IOStream` from an incoming connection."""
raise NotImplementedError()
def _handle_connection(self, connection, address):
if self.ssl_options is not None:
assert ssl, "Python 2.6+ and OpenSSL required for SSL"
try:
connection = ssl.wrap_socket(connection,
server_side=True,
do_handshake_on_connect=False,
**self.ssl_options)
except ssl.SSLError, err:
if err.args[0] == ssl.SSL_ERROR_EOF:
return connection.close()
else:
raise
except socket.error, err:
if err.args[0] == errno.ECONNABORTED:
return connection.close()
else:
raise
try:
if self.ssl_options is not None:
stream = SSLIOStream(connection, io_loop=self.io_loop)
else:
stream = IOStream(connection, io_loop=self.io_loop)
self.handle_stream(stream, address)
except Exception:
logging.error("Error in connection callback", exc_info=True)
而_handle_connection会被add_socket调用, 回到最上层, 其实是hello world程序中的http_server.listen(port) 这句, 发起listen, listen方法内会调用add_socket, 而handle_stream中实现的是调用HTTPConnection来处理一系列http协议中的connection部分. 在HTTPConnection中会处理callback, 这个callback就是Application类的__call__, 最后request数据会传给最终的逻辑处理类web.RequestHandler.
说起来特别费劲, 做了个思维导图(可能需要翻墙):