tornado源码阅读,从一个blog的入口开始走完框架核心(更新)

一、官方实例博客源码

官方blog实例,此处摘抄了main函数部分

:tornado.options.parse_command_line()http_server=tornado.httpserver.HTTPServer(Application())http_server.listen(options.port)tornado.ioloop.IOLoop.instance().start()if __name__ == “__main__”:main()

如上红色部分注释就是一个基本的流程。下面进入详细分析

二、详细分解main()

前面的设置与handler实例我们就暂时不看,直接从main()函数出发

:##下面这行是解析命令行参数,不多说tornado.options.parse_command_line()##这行有意思了,构造一个httpserver,其实大部分都是继承至tcpserver,注意参数Application()是个对象,而且是个可调用的对象,它里面有个方法__call__起了核心作用http_server=tornado.httpserver.HTTPServer(Application())##这行做的事可多了,后面详解http_server.listen(options.port)##这行就是构造事件或者说handler的循环队列,并执行触发事件的相应handler/注册的timeout事件/注册的callback等。tornado.ioloop.IOLoop.instance().start()三、http_server.listen(options.port)详解

从tcpserver中看看他做了什么事哈:

):###########调用netutil中的bind_socket,返回的是绑定的所有(IP,port)地址的socket########sockets = bind_sockets(port, address=address)###########自身的add_sockets方法中调用了netutil中的add_accept_handler########self.add_sockets(sockets)

看看add_sockets干了什么:

:if self.io_loop is None:self.io_loop = IOLoop.current()for sock in sockets:self._sockets[sock.fileno()] = sock ####记住这里回调的是_handle_connection,是处理请求的核心,稍后还会回头看add_accept_handler(sock,self._handle_connection,io_loop=self.io_loop)看看add_accept_handler做了什么::if io_loop is None:io_loop = IOLoop.current():while True:try:connection, address = sock.accept()except socket.error as e:if e.args[0] == errno.ECONNABORTED:continueraisecallback(connection, address)###把callback,也就是_handle_connection这个回调的handler注册到ioloop的多路复用(select/poll/epoll等)之上io_loop.add_handler(sock.fileno(), accept_handler, IOLoop.READ):self._handlers[fd] = stack_context.wrap(handler)self._impl.register(fd, events | self.ERROR)###之后就由ioloop.start内的循环poll发生的事件并回调相应的handler了四、handle_connection响应请求开始

这个函数位于tcpserver中:

::assert ssl, “Python 2.6+ and OpenSSL required for SSL”try:connection = ssl_wrap_socket(connection,self.ssl_options,server_side=True,do_handshake_on_connect=False)except ssl.SSLError as err:if err.args[0] == ssl.SSL_ERROR_EOF:return connection.close()else:raiseexcept socket.error as err:if errno_from_exception(err) in (errno.ECONNABORTED, errno.EINVAL):return connection.close()else:raisetry::stream = SSLIOStream(connection, io_loop=self.io_loop,max_buffer_size=self.max_buffer_size,read_chunk_size=self.read_chunk_size)else:stream = IOStream(connection, io_loop=self.io_loop,max_buffer_size=self.max_buffer_size,read_chunk_size=self.read_chunk_size)self.handle_stream(stream, address)except Exception:app_log.error(“Error in connection callback”, exc_info=True)

实例化了iostream对象,这个对象专门负责读写数据。然后是调用heepserver重写的handle_stream方法,将stream交给HTTPConnection处理,注意这里的request_callback是Application对象

:HTTPConnection(stream, address, self.request_callback,self.no_keep_alive, self.xheaders, self.protocol)

之后就到HTTPConnection初始化部分,核心就是_on_headers方法与read_until

def __init__(self, stream, address, request_callback, no_keep_alive=False,xheaders=False, protocol=None):self._header_callback = stack_context.wrap(self._on_headers)self.stream.set_close_callback(self._on_connection_close)###read_until可以暂时简单看作将数据读给_on_headers方法self.stream.read_until(b”\r\n\r\n”, self._header_callback):try:data = native_str(data.decode(‘latin1’))eol = data.find(“\r\n”)start_line = data[:eol]try:method, uri, version = start_line.split(” “)except ValueError:raise _BadRequestException(“Malformed HTTP request line”)if not version.startswith(“HTTP/”):raise _BadRequestException(“Malformed HTTP version in HTTP Request-Line”)try:headers = httputil.HTTPHeaders.parse(data[eol:])except ValueError:# Probably from split() if there was no ‘:’ in the lineraise _BadRequestException(“Malformed HTTP headers”)# HTTPRequest wants an IP, not a full socket addressif self.address_family in (socket.AF_INET, socket.AF_INET6):remote_ip = self.address[0]else:# Unix (or other) socket; fake the remote addressremote_ip = ‘0.0.0.0’self._request = HTTPRequest(connection=self, method=method, uri=uri, version=version,headers=headers, remote_ip=remote_ip, protocol=self.protocol)content_length = headers.get(“Content-Length”)if content_length:content_length = int(content_length)if content_length > self.stream.max_buffer_size:raise _BadRequestException(“Content-Length too long”)if headers.get(“Expect”) == “100-continue”:self.stream.write(b”HTTP/1.1 100 (Continue)\r\n\r\n”)self.stream.read_bytes(content_length, self._on_request_body)returnself.request_callback(self._request)except _BadRequestException as e:gen_log.info(“Malformed HTTP request from %s: %s”,self.address[0], e)self.close()return五、application的call完成最终相应::”””Called by HTTPServer to execute the request.”””transforms = [t(request) for t in self.transforms]handler = Noneargs = []kwargs = {}handlers = self._get_host_handlers(request)if not handlers:handler = RedirectHandler(self, request, url=”http://” + self.default_host + “/”)else:for spec in handlers:match = spec.regex.match(request.path)if match:handler = spec.handler_class(self, request, **spec.kwargs)if spec.regex.groups::if s is None:return sreturn escape.url_(s, encoding=None,plus=False)spec.regex.groupindex:kwargs = dict((str(k), unquote(v))for (k, v) in match.groupdict().items())else:args = [unquote(s) for s in match.groups()]handler:handler = ErrorHandler(self, request, status_code=404)self.settings.get(“debug”):with RequestHandler._template_loader_lock:for loader in RequestHandler._template_loaders.values():loader.reset()StaticFileHandler.reset()handler._execute(transforms, *args, **kwargs)return handler不会因为忧伤而风情万种。

tornado源码阅读,从一个blog的入口开始走完框架核心(更新)

相关文章:

你感兴趣的文章:

标签云: