Tornado HTTP

HTTP协议是建立在TCP基础之上的应用层协议,Tornado中TCP层由TCPServerIOStream负责,对HTTP报文的读取与解析则是由http1connection负责的。当HTTP报文被解析完毕后再交由某个delegate代理类实例负责进行后续处理。

HTTP服务器工作流程

4933701-3d743d6f98bda6d9.png
HTTP服务器工作流程

Web服务器工作的三部曲是什么呢?

  1. 创建:服务器创建Socket并在指定地址的端口上进行监听,等待客户端请求的到来。
  2. 监听:监听的Socket接收客户端的请求,当得到客户端的Socket时,通过客户端Socket与客户端保持通信。
  3. 处理:处理客户端的请求,首先客户端的Socket中读取HTTP请求的协议头,如果是POST则可能需要读取客户端上传的数据,让然后处理请求。最后准备好客户端所需的数据后通过客户端Socket回写给客户端。

例如:使用Python编写HTTP服务器

$ vim server.py
#!/usr/bin/python3
# -*- coding:utf-8 -*-

import socket

def handle_request(client):
    buf = client.recv(1024)
    print(buf)
    client.send(bytes("HTTP/1.1 200 OK\r\n\r\n", "utf-8"))
    client.send(bytes("hello world", "utf-8"))

def main():
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sock.bind(("127.0.0.1", 8000))
    sock.listen(3)
    while True:
        connection, address = sock.accept()
        handle_request(connection)
        connection.close()

if __name__ == "__main__":
    main()
$ python3 server.py

调试运行

$ curl http://127.0.0.1:8000
hello world

Tornado的HTTP服务器工作流程

Tornado Web程序编程思路

  1. 创建Web应用程序实例对象
  2. 定义实现路由映射表中的请求多处理器类
  3. 创建服务器实例并绑定端口
  4. 启动当前线程的事件循环

根据上述分析会将Web框架划分为两大部分

  1. 待请求阶段
    创建服务器Socket并监听端口
  2. 处理请求阶段
    当有客户端连接时接收请求并根据请求的不同做出相应的响应

当Tornado程序启动以及接收到客户端请求的过程可分为两部分

  1. 启动程序阶段/待请求阶段
  • 第一步:获取配置文件然后生成URL映射,即一个URL对应一个RequestHandler请求处理器,从而使请求处理器来处理制定URL发送的请求。
  • 第二步:创建服务器Socket对象并添加到Epoll中
  • 第三步:创建无限循环去监听Epoll
  1. 接收并处理请求阶段
  • 第一步:接收客户端Socket发送的请求socket.accept
  • 第二步:从请求中获取请求头信息,在根据请求头中的请求URL去匹配对应请求处理器RequestHandler
  • 第三步:成功匹配请求处理器
  • 第四步:将处理后的请求发送给客户端
  • 第五步:关闭客户端Socket

例如:使用Tornado实现单进程的HTTP服务器

$ vim server.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-

from tornado.options import define, options
from tornado.web import Application, RequestHandler
from tornado.httpserver import HTTPServer
from tornado.ioloop import IOLoop

# 自定义配置项
define("port", type=int, default=8000)
define("debug", type=bool, default=True)

# 请求处理器
class IndexHandler(RequestHandler):
    def get(self):
        print("index handler get method")
        self.write("hello world")

# 创建应用
# 定义路由表
urls = [
    (r"/index", IndexHandler)
]
# 定义应用配置
configs = dict(debug = options.debug)
# 指定路由和配置创建应用程序对象
app = Application(urls, configs)

# 程序主入口
if __name__ == "__main__":
    # 解析命令行参数
    options.parse_command_line()
    # 为应用创建HTTP服务器
    server = HTTPServer(app)
    print("http server start")
    # 为HTTP服务器设置监听端口
    server.listen(options.port)
    print("http server listen port %s" % options.port)
    # 开启事件循环接收客户端连接
    IOLoop.current().start()
$ python server.py

查看进程

$ ps -ef | grep server.py
jc        5047  3946  1 00:50 pts/0    00:00:00 python server.py
jc        5051  4169  0 00:50 pts/1    00:00:00 grep --color=auto server.py

访问测试

$ curl http://127.0.0.1:8000/index
hello world

注意

  • listen()方法只能在单进程模式中使用

例如:使用Tornado实现多进程的HTTP服务器

#!/usr/bin/env python
# -*- coding: utf-8 -*-

from tornado.options import define, options
from tornado.web import Application, RequestHandler
from tornado.httpserver import HTTPServer
from tornado.ioloop import IOLoop

# 自定义配置项
# 定义端口号
define("port", type=int, default=8000)
# 定义调试模式
define("debug", type=bool, default=True)
# 定义子进程个数
define("process", type=int, default=2)

# 请求处理器
class IndexHandler(RequestHandler):
    def get(self):
        print("index handler get method")
        self.write("hello world")


# 创建应用
# 定义路由表
urls = [
    (r"/index", IndexHandler)
]
# 定义应用配置
configs = dict(debug = options.debug)
# 指定路由和配置创建应用程序对象
app = Application(urls, configs)

# 程序主入口
if __name__ == "__main__":
    # 解析命令行参数
    options.parse_command_line()
    # 为应用创建HTTP服务器
    server = HTTPServer(app)
    print("http server start")
    # 为HTTP服务器绑定监听端口
    server.bind(options.port)
    # 为HTTP服务器开启监听,并设置开启进程的数量num_process。
    # 多进程数量默认为1
    # 多进程数量若小于等于0或为None则启动会根据及其硬件的CPU核心数量创建等同数量的子进程
    # 多进程数量大于0则表示实际创建子进程的数量
    server.start(options.process)
    print("http server listen port %s" % options.port)
    # 开启事件循环接收客户端连接
    IOLoop.current().start()

开启服务并查看进程数量

$ python server.py
$ ps -ef | grep server.py
jc        5079  3946  1 00:59 pts/0    00:00:00 python server.py
jc        5080  5079  0 00:59 pts/0    00:00:00 python server.py
jc        5081  5079  0 00:59 pts/0    00:00:00 python server.py
jc        5084  4169  0 00:59 pts/1    00:00:00 grep --color=auto server.py

注意

  • 每个子进程都会从父进程中复制一份IOLoop事件循环实例,若在创建子进程前修改了IOLoop实例则会影响到每个子进程。
  • 所有进程是由一条命令一次性开启的,所以是无法做到在不停服的情况下更新代码。
  • 所有进程共享同一个端口

当使用Tornado作为服务端时的工作流程是什么样的呢?

  1. Tornado在连接建立完毕后会将连接封装成为一个IOStream对象,这个对象可以异步的从连接中读写数据。
  2. Tornado中实现了HTTP1ServerConnectionHTTP1Connection两个类,它们依赖于底层的IOStream并从Socket中读写,并共同何做完成了HTTP 1.X协议。
  3. HTTP1Connection实际上主要用来处理HTTP事务,也就是由一条请求以及对应该请求的响应所组成的事务。HTTP1Connection实现了HTTP事务前半部分也就是对报文起始行、首行、主体进行读取并解析,而HTTP事务的后半部分则需要配合HTTPMessageDeletegate进行处理。
  4. HTTPMessageDelegate对经过HTTP1Connection解析后的报文会进行分配,然后由其他类如RequestHandler来执行具体的业务逻辑。其他类会生成响应并将响应发送到IOStream中,此时才表示这条HTTP事务已经完成。最后开发人员可以根据实际情况判断是否关闭连接。
  5. HTTP1ServerConnection则会不断地生成HTTP1Connection实例,也就是不断的处理HTTP事务,直至连接关闭为止。

Tornado服务器工作流程

首先按照socket->bind->listen的顺序创建listen socket监听客户端,并将每个listen socket的文件描述符fd注册到IOLoop的单例实例中,当listen socket可读写时回调_handle_events处理客户端请求,在与客户端通信的过程中使用IOStream封装了读和写缓冲区,实现与客户端的异步读写。

4933701-9bc06e3fc099935c.png
Tornado服务器工作流程

Tornado服务器核心模块

  1. IOLoop

Tornado为了实现高并发和高性能使用了一个IOLoop来处理Socket的读写事件,IOLoop是基于Linux的Epoll,可以高效地响应网络事件,这也是Tornado高效的保证。

  1. IOStream

为了在处理请求时实现对Socket的异步读写,Tornado实现了IOStream类用来处理Socket的异步读写操作。

  1. HTTPConnect

HTTPConnect类是用来处理HTTP请求,包括HTTP请求头、读取POST数据,调用用户自定义的处理方法,以及把响应数据写给客户端的Socket。

tornado.httpserver

HTTPServer继承于TCPServer,其__init__初始化函数中记录了连接到来时的回调函数即application对象的__call__方法被触发,然后是父类的初始化。父类TCPServer初始化主要是监听在特定地址的端口,当客户端发起连接时服务器接收并调用handle_stream方法。由于HTTPServer覆盖了父类TCPServerhandle_stream方法,并在该方法中生成HTTPConnection对象。HTTPConnection对象被构造时就立即开始了HTTP协议的处理。由于handle_stream被调用时是新连接的到来,此时缓冲区中都会有是有数据可读的。

class HTTPServer(
  TCPServer, 
  Configurable, 
  httputil.HTTPServerConnectionDeletegate
):
  • HTTPServerTCPServer的子类,关于Socket连接部分由TCPServer类实现。
  • HTTPServer只用于实现:处理连接connection和生成请求request

为了向后兼容,HTTPServerHTTPServerConnectionDelegate的子类,有一个将HTTPServerRequest作为参数的回调函数。这个委托delegate一般是tornado.web.Application

如果客户端的请求头中指定了Connection:keep-alive的话,HTTPServer支持活动的连接。而且HTTPServer是默认支持活动连接的。

如果xheaders选择设置成了True,HTTPServer同样支持x-Real-Ip/X-Forwarded-For以及X-Scheme/X-Forwarded-proto请求头,这样对所有的请求都会覆盖远程IP和 URL 协议。当在运行反向代理或负载均衡时,这些头文件会很有用。

  1. 处理连接handle_stream

HTTPServer默认需要重载父类TCPServerhandle_stream方法用来处理连接和生成请求

def handle_stream(self, stream, address):
  # 生成请求上下文
  context = _HTTPRequestContext(stream, addres, self.protocol)
  # 生成请求
  conn = HTTPServerConnection(stream, self.conn_params, context)
  # 加入到连接池,请求结束时需移除
  self._connections.add(conn)
  # 该连接开启服务
  conn.start_service(self)
  1. 生成请求 start_request
# 开始处理请求
def start_request(self, server_conn, request_conn):
  # 交由_ServerRequestAdapter生成Request请求
  return _ServerRequestAdapter(self, server_conn, request_conn)

HTTPServer的构造函数__init__中最重要的是request_callback,也就是说,当一个请求过来时应该如何处理。

Tornado的httpserver模块中具有HTTPServerHTTPConnectionHTTPRequest三个类。

#!/usr/bin/python3
# -*- coding:utf-8 -*-

from tornado.httpserver import HTTPServer
from tornado.ioloop import IOLoop

def handle_request(request):
    message = "method:{0}\nuri:{1}\nversion={2}".format(request.method, request.uri, request.version)
    for k,v in request.headers.items():
        message += k + ":" + v + "\n"
    request.connection.write(message)
    request.connection.finish()

def main():
    server = HTTPServer(handle_request, False)
    server.listen(8000)
    IOLoop.instance().start()

if __name__=="__main__":
    main()
  • HTTPServer是一个简单的HTTP服务器,主要作用是创建监听Socket,设置监听Socket的读事件处理器,最后调用HTTPConnection类处理整个连接。
  • HTTPConnection用于读取请求并解析,调用HTTPServer设置的回调函数(一般是Application)处理请求,并提供发送响应的接口。

httpserver模块是Tornado的HTTP服务器实现

引入tornado.httpserver模块

from tornado.httpserver import HTTPServer

创建HTTP服务器实例

urls = [
  (r"/", MainHandler)
]
app = tornado.web.Application(urls, debug=True)
httpServer = tornado.httpserver.HTTPServer(app)

监听端口,将服务器绑定到指定端口。

listen()方法只能在单进程模式中使用,若在多进程中可使用bind()方法和start()方法相结合。

单进程监听端口

httpServer.listen(8000)

多进程绑定并监听端口

# 将服务器绑定到指定端口
httpServer.bind(port)

# 指定开启进程的数量,num_processes表示进程的数量,默认为1.
# 若num_processes小于0或为None则会自动根据机器硬件的CPU核心数量创建等数量子进程,若num_processes大于0则会创建与num_processes相同数量的子进程。
httpServer.start(num_processes = 1)

HTTPConnection

HTTPConnection是HTTP协议在服务器的真正实现者,对于请求的读取和解析基本上是依赖HTTPHeaders完成的,对于响应方面的处理包括响应头、响应体的中间处理等在是在RequestHandlerflush方法和finish方法中完成的。

tornado.web

Tornado的Web框架tornado.web是在web.py文件中实现的,主要包含RequestHandler类和Application类。

  • RequestHandler类是对HTTP请求处理的封装
  • Application类是一些列请求的集合,构成一个Web应用程序。

A collection of request handleres that make up a web application

from tornado.web import RequestHandler, Application

RequestHandler

RequestHandler提供了一个针对HTTP请求处理的基类封装。主要功能包括:

  • 提供GET/POST/HEAD/DELETE/ PATCH/PUT/OPTIONS等方法的功能接口,开发时RequestHandler的子类重写这些方法以支持不同需求的请求处理。
  • 提供对HTTP请求的处理方法,包括对headers、页面元素、cookie的处理。
  • 提供对请求响应的方法,包括redirect页面冲重定向、write将数据写入IO缓冲区、render渲染模板等。
  • 提供辅助功能,如结束请求和响应、刷新输出缓冲区、对用户授权等处理。

RequestHandler封装了对应请求的所有信息和方法,利用HTTP向服务器传参的方式分为

  • 通过GET方法的查询字符串querystring,形式为key1=value1&key2=value2&key3=value3...
  • 通过POST方法的请求体body中发送的数据,比如表单数据、jsonxml...
  • 通过GET方法提取URI中的特定部分,比如PATHINFO模式中/blogs/2019/07/09,通过服务器路由中的正则表达式进行提取。
  • 通过HTTP报文的头header中增加自定义字段,如X-XSRFToken=xxxx

使用Tornado获取请求参数的方式

  1. 获取GET请求中查询字符串querystring参数
  • get_query_argument获取查询字符串querystring中的指定参数
val = get_query_argument(name, default=_ARG_DEFAULT, strip=True)

get_query_argument会从请求查询字符串中获取指定参数名name的值,如果出现多个同名参数则返回最后一个值。

参数列表

参数1:name表示查询字符串中指定的参数名
参数2:default表示当未传入name参数时返回的默认值,若default默认值未设置则会抛出tornado.web.MissingArgumentError异常。
参数3:strip表示是否过滤左右两边的空白字符,默认过滤strip=True

例如

$ vim server.php
#! /usr/bin/python3
# encoding=utf-8

from tornado.options import define, options
from tornado.web import Application, RequestHandler, url
from tornado.httpserver import HTTPServer
from tornado.ioloop import IOLoop

define("port", type=int, default=8000, help="run server on the given port")

class IndexHandler(RequestHandler):
    def get(self):
        self.write("hello world")
    def post(self):
        self.write("post")

class UserHandler(RequestHandler):
    def get(self):
        uid = self.get_query_argument("uid", strip=True)
        print("uid = " + str(uid))

        username = self.get_query_argument("username", strip=True)
        print("username = %s" %username.encode("utf-8"))

        index_url = self.reverse_url("index_url")
        print(index_url)

        self.write("success")
        # self.write("uid=%s username=%s index_url=%s" %uid %username.encode("utf-8") %index_url)

urls = [
    url(r"/", IndexHandler, name="index_url"),
    (r"/user", UserHandler)
]

settings = dict(debug=True)

if __name__ == "__main__":
    options.parse_command_line()
    app = Application(urls, settings)
    server = HTTPServer(app)
    server.listen(options.port)
    IOLoop.current().start()

运行服务器

$ python server.php

客户端访问,注意Linux下&取地址符表示进程后台运行,所以在URL中必须进行转义才能获取到参数。

$ curl http://127.0.0.1:8000/user?uid=100\&username=中文
  • get_query_arguments获取查询字符串querystring中参数
list = get_query_arguments(name, strip=True)

get_query_arguments用于从请求的查询字符串中返回指定参数名name的值,返回的是list列表,若未找到name参数则返回空列表[]

  1. 获取POST请求体body参数
  • get_body_argument获取请求体参数

对于HTTP请求体body中的数据,必须要求格式为字符串且表单编码格式与URL中的请求字符串格式一致,即key1=value1&key2=value2&key3=value3...的形式。

HTTP报文头Header中的Content-Type内容类型必须为application/x-www-form-urlencodedmultipart/form-data。对于请求体数据为JSONXML的则无法获取。

val = get_body_argument(name, default=_ARG_DEFAULT, strip=True)

get_body_argument会从请求体body中获取指定参数名name的值,若出现多个同名参数则返回最后一个的值。

  • get_body_arguments 获取请求体参数
list = get_body_arguments(name, strip=True)

get_body_arguments表示从请求体中返回指定参数名name的值,返回list列表,若未找到name参数则返回空列表[]

  1. 获取请求参数
  • get_argument
val = get_argument(name, default=_ARG_DEFAULT, strip=True)

get_argument表示从POST请求体bodyGET查询字符串querystring中返回指定参数名name的值,如果出现多个同名参数则返回最后一个的值。

  • get_arguments
list = get_arguments(name, strip=True)

get_arguments表示从POST请求体bodyGET查询字符串querystring中返回指定参数名name的值,返回值类型为list列表,若为找到name参数则返回空列表[]

  1. 获取请求信息

RequestHandler.request对象存储了请求的相关信息,具体属性包括:

  • RequestHandler.request.method 表示HTTP的请求方式,如GETPOST
  • RequestHandler.request.host 表示HTTP中被请求的主机名
  • RequestHandler.request.uri 表示HTTP请求的完整资源标识,包括路径和查询字符串。
  • RequestHandler.request.path 表示HTTP请求中URL的路径部分
  • RequestHandler.request.query 表示HTTP请求中URL的查询字符串部分
  • RequestHandler.request.version 表示HTTP请求所使用的HTTP版本号
  • RequestHandler.request.headers 表示HTTP请求的协议头,是类字典型的对象,支持关键字索引的方式获取特定协议头字段,如request.headers["Content-Type"]
  • RequestHandler.request.body 表示HTTP请求体数据
  • RequestHandler.request.remote_ip表示HTTP请求中客户端的IP地址
  • RequesteHandler.request.files 表示HTTP请求中用户上传的文件,字典类型。
# form_filename1字典中的键名表示的是表单对应项的名字
request.files["form_filename1"][0]["body"]

文件上传

文件上传时可使用tornado.httputil.HTTPFile接收文件,HTTPFile是接收到的文件对象,它包含三个属性。

  • 属性1:HTTPFile.filename 表示文件的实际名字
  • 属性2:HTTPFile.body 表示文件的数据实体
  • 属性3:HTTPFile.content_type 表示文件的类型

HTTPFile中的三个对象属性可以像字典一样支持关键字索引。


输出数据流

write(chunk)

writechunk数据写入到缓冲区,如果多次使用write方法则会不断追加响应内容,最终会将所有写入到缓冲区的内容一起作为本次请求的响应一起输出。

如果传入的chunkdict字典类型,Tornado会自动将其识别为JSON,并设置Header报头的Content-Type字段为application/json

如果传入的chunklist列表类型,考虑到安全问题list列表将不会被转换为JSON格式。

finish(chunk)

finish表示完成响应并结束本次请求,通常情况下请求会在return时自动调用finish方法,只有在使用异步装饰器@asynchronous或其他将._auto_finish设置为False时才需要手动调用finish方法。

#! /usr/bin/python3
# encoding=utf-8

from tornado.options import define, options
from tornado.web import Application, RequestHandler, url
from tornado.httpserver import HTTPServer
from tornado.ioloop import IOLoop

define("port", type=int, default=8000, help="run server on the given port")

class IndexHandler(RequestHandler):
    def get(self):
        self.write("hello world")
    def post(self):
        self.write("post")

class UserHandler(RequestHandler):
    def get(self):
        uid = self.get_query_argument("uid", strip=True)
        print("uid = " + str(uid))

        username = self.get_query_argument("username", strip=True)
        print("username = %s" %username)

        index_url = self.reverse_url("index_url")
        print(index_url)

        jsonstr= {"uid":uid, "username":username,"url":index_url}
        self.finish(jsonstr)

urls = [
    url(r"/", IndexHandler, name="index_url"),
    (r"/user", UserHandler)
]

settings = dict(debug=True)

if __name__ == "__main__":
    options.parse_command_line()
    app = Application(urls, settings)
    server = HTTPServer(app)
    server.listen(options.port)
    IOLoop.current().start()

flush()

flush方法会将缓冲区的数据写入到socket中,如果设置了回调函数callback,会在完成数据写入后回调。需要在注意的是同一时间只能有一个等待的flush callback,如果上一次的flush callback还没有执行,又来了新的flush则上一次的flush callback会被忽略掉。

Application

A collection of request handle that mak up a web application. Instances of this class are callbable and can be passed directly to HTTPServer to server the application.

Application类初始化

Application是Tornado Web框架的核心应用类,是与服务器对接的接口。保存了路由信息,其初始化的第一个 参数是一个路由映射元组的列表,可使用listen方法创建一个HTTP服务器实例并绑定指定的端口。

from tornado.web import Application
app = Application(urls, settings)

Application类初始化的第一个参数是接收一个(regexp, requste_class)形式的列表,参数指定了针对不同URL请求所采取的处理方法,包括对静态文件请求的处理web.StaticFileHandler

Application类中实现了__call__调用函数,这样该类就成为了可调用的对象,并由HTTPServer来进行调用。__call__函数会遍历Application类中的handlers列表,匹配到相应的URL后通过handler._execute进行相应处理。如果没有匹配到URL则会调用ErrorHandler

参数1:路由映射表urls

在构建路由映射表时使用的是二元元组

urls = [(r"/", IndexHandler),]

对于路由映射表中的路由可传入多个路由规则

from tornado.web import Application, RequestHandler,  url

urls = [
  (r"/", IndexHandler),
  (r"/create", CreateHandler, {"pid": 100}),
  url(r"/update", UpdateHandler, {"id":100}, name="update_url")
]

路由中的字典{k:v}会传入到对应的RequestHandlerinitialize()方法中

from tornado.web import RequestHandler, url

class TestHandler(RequestHandler):
  def initialize(self, k):
    self.k = k
  def get(self):
    self.write(self.k)

urls = [
  (r"/", TestHandler, {k:v})
]
app = tornado.web.Application(urls)

路由中的name字段不能再使用元组而应使用tornado.web.url来构建,name是给路由起一个别名,可通过调用RequestHandler.reverse_url(name)来获取名字对应的URL。

$ vim server.py
#! /usr/bin/python
# encoding=utf-8

from tornado.options import define, options
from tornado.web import Application, RequestHandler, url
from tornado.httpserver import HTTPServer
from tornado.ioloop import IOLoop

define("port", type=int, default=8000, help="run server on the given port")

class IndexHandler(RequestHandler):
    def initialize(self, id):
        self.id = id
    def get(self):
        id = self.get_query_argument("id", strip=True)
        # self.write(id)

        index_url = self.reverse_url("index_url")
        self.write("url=%s" %index_url)
    def post(self):
        self.write("post")


urls = [
    url(r"/", IndexHandler, {"id":100}, name="index_url")       
]

settings = dict(debug=True)

if __name__ == "__main__":
    options.parse_command_line()
    app = Application(urls, settings)
    server = HTTPServer(app)
    server.listen(options.port)
    IOLoop.current().start()
$ python server.py

参数2:应用配置参数settings

Application类传递给构造器的附加关键字参数保存在settings字典中,settings被用于自定义Tornado应用的多个方面。

settins = dict(debug=True)

debug用于设置Tornado是否工作在调试模式,默认为False即工作在生产模式,当设置debug=True后Tornado会工作在开发调试模式,在此种调试模式下Tornado提供了几种特性:

  1. 自动重启

Tornado应用会监控源代码文件,当有改动保存后会自动重启程序,减少手工重启程序的次数。需要注意的时,一旦保存的更改有错误,自动重启会导致程序报错而退出,从而需要保存修正错误后手动启动程序。此特性可以通过autoreload=True设置。

settings = dict(autoreload=True)
  1. 取消缓存编译的模板
settings = dict(compiled_template_cache=False)
  1. 取消缓存静态文件hash
settings = dict(static_hash_cache=False)
  1. 提供追踪信息

RequestHandler或其子类抛出一个异常而未捕获后,会生成一个包含追踪信息的页面。

settings = dict(serve_traceback=True)

设置应用配置

import tornado.web

tornado.web.Application(urls, settings)
from tornado.web import Application, RequestHandler, url

urls = [
  url(r"/", IndexHandler)
]

settings = dict(debug=True)

app = Application(urls, settings)

tornado.ioloop

Tonado的核心IO循环模块是tornado.io,它封装了Linux的Epoll和BSD的kqueue,是Tornado高性能的基础。

  • tornado.ioloop是全局Tornado的IO事件循环,是服务器的引擎核心。
  • tornado.ioloop是核心IO循环模块,封装了Linux的epoll和BSD的kqueue,是Tornado高性能处理的核心。
  • tornado.ioloop.IOLoop.current()返回当前线程的IOLoop实例对象
  • tornado.ioloop.IOLoop.current().start() 用于启动IOLoop实例对象的IO循环并开启监听
4933701-70549aaf234d4447.png
ioloop工作原理
# 加载Tornado核心IO事件循环模块
import tornado.ioloop

# 默认Tornado的ioloop实例
tornado.ioloop.IOLoop.current()

tornado.options

from tornado.options import define, options

options表示全局的options对象,可用于全局参数的定义、存储、转换,所有定义的选项变量都会作为options对象的属性。

tornado.options.optins

define方法用来定义options选项变量,定义的变量可以在全局tornado.options.options中获取使用。

tornado.options.define(name, default, type, multiple, help)
  • name 表示选项的变量名称,必须保证全局唯一,否则会报Option xxx already defined in...错误。
  • default表示选项变量的默认值,若不传入则默认为None
  • type表示选项变量的类型,从命令行或配置文件导入参数时Tornado会根据此类型转换输入的值,若转换 失败则 报错,转换的类型支持strfloatintdatetimetimedate。若未设置则会根据default的值自动进行推断,若default默认值也没有设置则不会再进行转换,可以通过利用设置type类型字段来过滤不正确的输入。
  • multiple选项变量的值是否可为多个,布尔类型,默认为False,如果 multipleTrue则设置选项变量时值与值之间使用英文逗号分隔,此时选项变量是一个list列表。若默认值和输入均未设置则为空列表[]
  • help选项变量的帮助提示信息,在命令行启动Tornado时会加入命令行参数--help,可以查看所有选项变量的信息。

define用于定义端口用于指定HTTP服务监听的端口,如果命令行中带有port同名参数则会称为全局tornado.options的属性,若没有则使用define定义。

tornado.options.define('port', default=8000, type=int, help="this is the port >for application")

parse_command_line转换命令行参数,并将转换后的值对应的设置到全局options对象相关属性上。

tornado.options.parse_command_line()

命令行追加参数的方式是使用--myoption=myvalue

$ python server.py --port=8000

parse_config_file根据配置文件配置文件获取参数

tornado.options.parse_config_file(filepath)

从配置文件导入option时配置文件中的格式为

tornado.options.parse_config_file("./config")

使用parse_config_file()函数时配置文件的编写格式需按照Python的语法要求,其优势是可以直接将配置文件的参数文件转换设置到全局对象tornado.options.options上。

$ vim config.py
port = 8000
debug =  True
ip = ["192.168.56.100", "192.168.56.101", "192.168.56.102"]
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值