HTTP协议是建立在TCP基础之上的应用层协议,Tornado中TCP层由TCPServer
和IOStream
负责,对HTTP报文的读取与解析则是由http1connection
负责的。当HTTP报文被解析完毕后再交由某个delegate
代理类实例负责进行后续处理。
HTTP服务器工作流程
Web服务器工作的三部曲是什么呢?
- 创建:服务器创建Socket并在指定地址的端口上进行监听,等待客户端请求的到来。
- 监听:监听的Socket接收客户端的请求,当得到客户端的Socket时,通过客户端Socket与客户端保持通信。
- 处理:处理客户端的请求,首先客户端的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程序编程思路
- 创建Web应用程序实例对象
- 定义实现路由映射表中的请求多处理器类
- 创建服务器实例并绑定端口
- 启动当前线程的事件循环
根据上述分析会将Web框架划分为两大部分
- 待请求阶段
创建服务器Socket并监听端口 - 处理请求阶段
当有客户端连接时接收请求并根据请求的不同做出相应的响应
当Tornado程序启动以及接收到客户端请求的过程可分为两部分
- 启动程序阶段/待请求阶段
- 第一步:获取配置文件然后生成URL映射,即一个URL对应一个
RequestHandler
请求处理器,从而使请求处理器来处理制定URL发送的请求。 - 第二步:创建服务器Socket对象并添加到Epoll中
- 第三步:创建无限循环去监听Epoll
- 接收并处理请求阶段
- 第一步:接收客户端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作为服务端时的工作流程是什么样的呢?
- Tornado在连接建立完毕后会将连接封装成为一个
IOStream
对象,这个对象可以异步的从连接中读写数据。 - Tornado中实现了
HTTP1ServerConnection
和HTTP1Connection
两个类,它们依赖于底层的IOStream
并从Socket中读写,并共同何做完成了HTTP 1.X协议。 -
HTTP1Connection
实际上主要用来处理HTTP事务,也就是由一条请求以及对应该请求的响应所组成的事务。HTTP1Connection
实现了HTTP事务前半部分也就是对报文起始行、首行、主体进行读取并解析,而HTTP事务的后半部分则需要配合HTTPMessageDeletegate
进行处理。 -
HTTPMessageDelegate
对经过HTTP1Connection
解析后的报文会进行分配,然后由其他类如RequestHandler
来执行具体的业务逻辑。其他类会生成响应并将响应发送到IOStream
中,此时才表示这条HTTP事务已经完成。最后开发人员可以根据实际情况判断是否关闭连接。 -
HTTP1ServerConnection
则会不断地生成HTTP1Connection
实例,也就是不断的处理HTTP事务,直至连接关闭为止。
Tornado服务器工作流程
首先按照socket->bind->listen
的顺序创建listen socket
监听客户端,并将每个listen socket
的文件描述符fd
注册到IOLoop
的单例实例中,当listen socket
可读写时回调_handle_events
处理客户端请求,在与客户端通信的过程中使用IOStream
封装了读和写缓冲区,实现与客户端的异步读写。
Tornado服务器核心模块
- IOLoop
Tornado为了实现高并发和高性能使用了一个IOLoop来处理Socket的读写事件,IOLoop是基于Linux的Epoll,可以高效地响应网络事件,这也是Tornado高效的保证。
- IOStream
为了在处理请求时实现对Socket的异步读写,Tornado实现了IOStream类用来处理Socket的异步读写操作。
- HTTPConnect
HTTPConnect类是用来处理HTTP请求,包括HTTP请求头、读取POST数据,调用用户自定义的处理方法,以及把响应数据写给客户端的Socket。
tornado.httpserver
HTTPServer
继承于TCPServer
,其__init__
初始化函数中记录了连接到来时的回调函数即application
对象的__call__
方法被触发,然后是父类的初始化。父类TCPServer
初始化主要是监听在特定地址的端口,当客户端发起连接时服务器接收并调用handle_stream
方法。由于HTTPServer
覆盖了父类TCPServer
的handle_stream
方法,并在该方法中生成HTTPConnection
对象。HTTPConnection
对象被构造时就立即开始了HTTP协议的处理。由于handle_stream
被调用时是新连接的到来,此时缓冲区中都会有是有数据可读的。
class HTTPServer(
TCPServer,
Configurable,
httputil.HTTPServerConnectionDeletegate
):
-
HTTPServer
是TCPServer
的子类,关于Socket连接部分由TCPServer
类实现。 -
HTTPServer
只用于实现:处理连接connection
和生成请求request
为了向后兼容,HTTPServer
是HTTPServerConnectionDelegate
的子类,有一个将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 协议。当在运行反向代理或负载均衡时,这些头文件会很有用。
- 处理连接
handle_stream
HTTPServer
默认需要重载父类TCPServer
的handle_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)
- 生成请求
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
模块中具有HTTPServer
、HTTPConnection
、HTTPRequest
三个类。
#!/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
完成的,对于响应方面的处理包括响应头、响应体的中间处理等在是在RequestHandler
的flush
方法和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
中发送的数据,比如表单数据、json
、xml
... - 通过
GET
方法提取URI中的特定部分,比如PATHINFO
模式中/blogs/2019/07/09
,通过服务器路由中的正则表达式进行提取。 - 通过HTTP报文的头
header
中增加自定义字段,如X-XSRFToken=xxxx
。
使用Tornado获取请求参数的方式
- 获取
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
参数则返回空列表[]
。
- 获取
POST
请求体body
参数
-
get_body_argument
获取请求体参数
对于HTTP请求体body
中的数据,必须要求格式为字符串且表单编码格式与URL中的请求字符串格式一致,即key1=value1&key2=value2&key3=value3...
的形式。
HTTP报文头Header
中的Content-Type
内容类型必须为application/x-www-form-urlencoded
或multipart/form-data
。对于请求体数据为JSON
或XML
的则无法获取。
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
参数则返回空列表[]
。
- 获取请求参数
get_argument
val = get_argument(name, default=_ARG_DEFAULT, strip=True)
get_argument
表示从POST
请求体body
和GET
查询字符串querystring
中返回指定参数名name
的值,如果出现多个同名参数则返回最后一个的值。
get_arguments
list = get_arguments(name, strip=True)
get_arguments
表示从POST
请求体body
或GET
查询字符串querystring
中返回指定参数名name
的值,返回值类型为list
列表,若为找到name
参数则返回空列表[]
。
- 获取请求信息
RequestHandler.request
对象存储了请求的相关信息,具体属性包括:
-
RequestHandler.request.method
表示HTTP的请求方式,如GET
或POST
。 -
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)
write
将chunk
数据写入到缓冲区,如果多次使用write
方法则会不断追加响应内容,最终会将所有写入到缓冲区的内容一起作为本次请求的响应一起输出。
如果传入的chunk
是dict
字典类型,Tornado会自动将其识别为JSON,并设置Header
报头的Content-Type
字段为application/json
。
如果传入的chunk
是list
列表类型,考虑到安全问题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}
会传入到对应的RequestHandler
的initialize()
方法中
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提供了几种特性:
- 自动重启
Tornado应用会监控源代码文件,当有改动保存后会自动重启程序,减少手工重启程序的次数。需要注意的时,一旦保存的更改有错误,自动重启会导致程序报错而退出,从而需要保存修正错误后手动启动程序。此特性可以通过autoreload=True
设置。
settings = dict(autoreload=True)
- 取消缓存编译的模板
settings = dict(compiled_template_cache=False)
- 取消缓存静态文件
hash
值
settings = dict(static_hash_cache=False)
- 提供追踪信息
当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循环并开启监听
# 加载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会根据此类型转换输入的值,若转换 失败则 报错,转换的类型支持str
、float
、int
、datetime
、timedate
。若未设置则会根据default
的值自动进行推断,若default
默认值也没有设置则不会再进行转换,可以通过利用设置type
类型字段来过滤不正确的输入。 -
multiple
选项变量的值是否可为多个,布尔类型,默认为False
,如果multiple
为True
则设置选项变量时值与值之间使用英文逗号分隔,此时选项变量是一个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"]