🍺Web服务器系列相关文章编写如下🍺:
- 🎈【Web开发】Node.js实现Web服务器(http模块)🎈
- 🎈【Web开发】Node.js实现Web服务器(express模块)🎈
- 🎈【Web开发】Python实现Web服务器(Flask入门)🎈
- 🎈【Web开发】Python实现Web服务器(Flask测试)🎈
- 🎈【Web开发】Python实现Web服务器(Tornado入门)🎈
- 🎈【Web开发】Python实现Web服务器(Tornado+flask+nginx)🎈
- 🎈【Web开发】Python实现Web服务器(FastAPI)🎈
- 🎈【Web开发】Android手机上基于Termux实现Web服务器(Python、node.js)🎈
1、简介
1.1 什么是Tornado?
Tornado龙卷风是一个开源的网络服务器框架(一个python web框架和异步网络库),它是基于社交聚合网站FriendFeed的实时信息服务开发而来的。2007年由4名Google前软件工程师一起创办了FriendFeed,旨在使用户能够方便地跟踪好友在Facebook和Twitter等多个社交网站上的活动。
- Tornado通过使用非阻塞网络I/O,Tornado可以扩展到数万个开放连接,使其非常适合 long polling , WebSockets 以及其他需要与每个用户建立长期连接的应用程序。
- Tornado与现代主流的Web服务器框架有着明显的区别:它使非阻塞式的服务器,速度相当快。这得益于其非阻塞的方式和对epoll的运用。Tornado每秒可以处理数以千计的连接。
- Tornado是实时Web服务的一个理想框架,它非常适合开发长轮询、WebSocket和需要与每个用户建立持久连接的应用。
- 与Node.js相同的是,Tornado也采用的是单进程单线程异步IO的网络模型,它们都可以编写异步非阻塞的程序。
1.2 Tornado的功能模块
Tornado的主要功能模块:
- (1)Web framework(Web框架)
tornado.web、tornado.template、tornado.routing、tornado.escape、tornado.locale、tornado.websocket等。 - (2)HTTP servers and clients(HTTP 服务器和客户端)
tornado.httpserver、tornado.httpclient、tornado.httputil、tornado.http1connection等。 - (3)Asynchronous networking(异步网络)
tornado.ioloop、tornado.iostream、tornado.netutil、tornado.tcpclient、tornado.tcpserver等。 - (4)Coroutines and concurrency(协程和并发)
tornado.gen 、tornado.locks、tornado.queues、tornado.process等。 - (5)Integration with other services(与其他服务集成)
tornado.auth、tornado.wsgi、tornado.platform.caresresolver、tornado.platform.twisted、tornado.platform.asyncio等。 - (6)Utilities (实用程序)
tornado.autoreload、tornado.concurrent、tornado.log、tornado.options、tornado.testing、tornado.util等。
其中Tornado的服务器三个底层核心模块:
- (1)httpserver 服务于web模块的一个简单的HTTP服务器的实现
- (2)iostream 对非阻塞式的socket的封装以便于常见读写操作
- (3)ioloop 核心的I/O循环
2、安装
https://github.com/tornadoweb/tornado
https://www.tornadoweb.org/en/stable/
Tornado与标准库集成 asyncio 模块和共享相同的事件循环(默认情况下,从Tornado 5.0开始)。通常,设计用于 asyncio 可以与 Tornado 自由混合。
- 安装最新版本执行如下命令:
pip install tornado
- 运行结果:
- 安装版本5.1执行如下命令:
pip install tornado==5.1.1
3、入门示例
3.1 tornado.web
tornado.web提供了一个具有异步功能的简单 Web 框架,允许它扩展到大量打开的连接,使其成为长轮询的理想选择。
import asyncio
import tornado.web
import platform
if platform.system() == "Windows":
import asyncio
asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
class MainHandler(tornado.web.RequestHandler):
def get(self):
self.write("Hello, world, 爱看书的小沐, 2022!")
def make_app():
return tornado.web.Application([
(r"/", MainHandler),
])
async def main():
app = make_app()
app.listen(8888)
await asyncio.Event().wait()
if __name__ == "__main__":
asyncio.run(main())
或者
import tornado.ioloop
import tornado.web
import platform
if platform.system() == "Windows":
import asyncio
asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
class MainHandler(tornado.web.RequestHandler):
def get(self):
self.write("Hello, world, 爱看书的小沐, 2022!")
if __name__ == "__main__":
application = tornado.web.Application([
(r"/", MainHandler),
])
application.listen(8888)
tornado.ioloop.IOLoop.current().start()
或者
import tornado.httpserver
import tornado.ioloop
import tornado.options
import tornado.web
from tornado.options import define, options
import platform
if platform.system() == "Windows":
import asyncio
asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
define("port", default=8888, help="run on the given port", type=int)
class MainHandler(tornado.web.RequestHandler):
def get(self):
self.write("Hello, world")
def main():
tornado.options.parse_command_line()
application = tornado.web.Application([(r"/", MainHandler)])
http_server = tornado.httpserver.HTTPServer(application)
http_server.listen(options.port)
tornado.ioloop.IOLoop.current().start()
if __name__ == "__main__":
main()
- 服务端运行结果:
- 测试客户端运行结果:
- 1.发送get请求
curl http://127.0.0.1:8888
- 2.检查响应头
curl -I http://127.0.0.1:8888
- 3.显示回应时间
curl -s -w "%{time_total}\n" -o null http://127.0.0.1:8888
- 4.发送请求头
curl -H 'Cache-Control: no-cache' -I http://127.0.0.1:8888
3.2 tornado.template
一个简单的模板系统,将模板编译成 Python 代码。
- test_tornado.html:
<html>
<head>
<title>{{ title }}</title>
</head>
<body>
<div>爱看书的小沐的课程表</div>
<ul>
{% for item in items %}
<li>{{ escape(item) }}</li>
{% end %}
</ul>
</body>
</html>
- test_tornado.py:
import tornado.ioloop
import tornado.web
import platform
if platform.system() == "Windows":
import asyncio
asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
class MainHandler(tornado.web.RequestHandler):
def get(self):
self.write('<a href="%s">link to class 1</a>' %
self.reverse_url("class", "1"))
items = ["星期一:体育课", "星期二:数学课", "星期三:语文课"]
self.render("templates\\test_tornado.html", title="My title", items=items)
class MyFormHandler(tornado.web.RequestHandler):
def get(self):
self.write('<html><body><form action="/myform" method="POST">'
'<input type="text" name="message">'
'<input type="submit" value="Submit">'
'</form></body></html>')
def post(self):
self.set_header("Content-Type", "text/plain")
self.write("You wrote " + self.get_body_argument("message"))
class ClassHandler(tornado.web.RequestHandler):
def initialize(self, db):
self.db = db
def get(self, class_id):
self.write("this is class %s" % db[min(int(class_id), len(db)-1)])
self.write(":<br>我们,这29个人,怀抱活力与梦想。前方有彩虹,前方有鲜花。")
db = ["zero", "one", "two"]
if __name__ == "__main__":
app = tornado.web.Application([
tornado.web.url(r"/", MainHandler),
tornado.web.url(r"/myform", MyFormHandler),
tornado.web.url(r"/class/([0-9]+)", ClassHandler, dict(db=db), name="class")
])
app.listen(8888)
tornado.ioloop.IOLoop.current().start()
- 运行结果:
3.3 tornado.wsgi
支持Tornado Web框架的wsgi。
wsgi是Web服务器的python标准,允许Tornado与其他python Web框架和服务器之间的互操作性。
WSGI是 同步的 接口,而Tornado的并发模型是基于单线程异步执行的。这意味着使用Tornado的 WSGIContainer 是 不可扩展 比在多线程的wsgi服务器上运行相同的应用程序 gunicorn 或 uwsgi . 使用 WSGIContainer 只有当Tornado和WSGi在同一个过程中结合起来的好处大于减少的可伸缩性时。
- test_wsgi.py
from tornado import ioloop
from tornado import wsgi
from tornado import httpserver
from tornado.web import Application
import platform
if platform.system() == "Windows":
import asyncio
asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
def simple_app(environ, start_response):
status = "200 OK"
response_headers = [("Content-type", "text/plain")]
start_response(status, response_headers)
return [b"Hello world, WSGI!\n"]
container = wsgi.WSGIContainer(simple_app)
http_server = httpserver.HTTPServer(container)
http_server.listen(8888)
ioloop.IOLoop.current().start()
- 运行结果:
3.4 tornado.websocket
WebSockets允许浏览器和服务器之间的双向通信。
所有主流浏览器的当前版本都支持 WebSockets,尽管不支持 WebSockets 的旧版本仍在使用(详情请参阅http://caniuse.com/websockets)。
此模块实现在中定义的WebSocket协议的最终版本。 RFC 6455 . 某些浏览器版本(特别是Safari 5.x)实现了早期的协议草案(称为“草案76”),与本模块不兼容。
- test_websocket.py(一对一方式)
from tornado import ioloop
from tornado.web import Application
from tornado.websocket import WebSocketHandler
import urllib
import platform
if platform.system() == "Windows":
import asyncio
asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
class EchoWebSocket(WebSocketHandler):
def open(self):
print("WebSocket opened")
def on_message(self, message):
print("message from client:" + message)
self.write_message(u"You said: " + message)
def on_close(self):
print("WebSocket closed")
# 这是针对浏览器上的跨站点脚本攻击的安全保护,
# 因为允许 WebSocket 绕过通常的同源策略并且不使用 CORS 标头。
# 允许所有跨域通讯,或允许来自您网站的任何子域的连接
def check_origin(self, origin):
parsed_origin = urllib.parse.urlparse(origin)
print(parsed_origin)
# return parsed_origin.netloc.endswith(".mydomain.com")
return True
def set_default_headers(self):
self.set_header('Access-Control-Allow-Origin', '*')
self.set_header('Access-Control-Allow-Methods', 'POST, GET, OPTIONS')
self.set_header('Access-Control-Max-Age', 1000)
self.set_header('Access-Control-Allow-Headers', '*')
if __name__ == "__main__":
application = Application([
# (r"/", EchoWebSocket),
(r"/websocket", EchoWebSocket),
])
application.listen(8888)
ioloop.IOLoop.current().start()
- test_websocket.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Tornado Websocket Test</title>
</head>
<body>
<body onload='onLoad();'>
Message to send: <input type="text" id="msg"/>
<input type="button" onclick="sendMsg();" value="发送"/>
</body>
</body>
<script type="text/javascript">
var ws;
function onLoad() {
ws = new WebSocket("ws://localhost:8888/websocket");
ws.onopen = function() {
ws.send("Hello, world");
};
ws.onmessage = function (evt) {
//alert(evt.data);
console.log(evt.data)
};
}
function sendMsg() {
ws.send(document.getElementById('msg').value);
}
</script>
</html>
- 运行结果:
-
- test_websocket_mutil.py(一对多方式)
from tornado import ioloop
from tornado.web import Application
from tornado.websocket import WebSocketHandler
import urllib
import platform
if platform.system() == "Windows":
import asyncio
asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
clients = set()
class EchoWebSocket(WebSocketHandler):
def open(self):
print("WebSocket opened")
clients.add(self)
def on_message(self, message):
print("message from client:" + message)
self.write_message(u"You said: " + message)
for c in clients:
c.write_message(u"server said: " + message)
def on_close(self):
print("WebSocket closed")
clients.discard(self)
# 这是针对浏览器上的跨站点脚本攻击的安全保护,因为允许 WebSocket 绕过通常的同源策略并且不使用 CORS 标头。
# 允许所有跨域通讯,或允许来自您网站的任何子域的连接
def check_origin(self, origin):
parsed_origin = urllib.parse.urlparse(origin)
print(parsed_origin)
# return parsed_origin.netloc.endswith(".mydomain.com")
return True
def set_default_headers(self):
self.set_header('Access-Control-Allow-Origin', '*')
self.set_header('Access-Control-Allow-Methods', 'POST, GET, OPTIONS')
self.set_header('Access-Control-Max-Age', 1000)
self.set_header('Access-Control-Allow-Headers', '*')
def ServerDogHandler():
for c in clients:
c.write_message(u"server said: a heartbeat meesage.")
if __name__ == "__main__":
application = Application([
# (r"/", EchoWebSocket),
(r"/websocket", EchoWebSocket),
])
application.listen(8888)
ioloop.PeriodicCallback(ServerDogHandler, 1000).start()
ioloop.IOLoop.current().start()
- 运行结果:
3.5 tornado.httpserver
tornado.httpserver — Non-blocking HTTP server
一个非阻塞的单线程 HTTP 服务器。典型的应用程序与类几乎没有直接交互,HTTPServer 除了在进程开始时启动服务器(甚至通常通过 间接完成tornado.web.Application.listen)。
HTTPServer初始化遵循三种模式之一:
- listen:简单的单进程:
在很多情况下,tornado.web.Application.listen可以用来避免显式创建HTTPServer.
server = HTTPServer(app)
server.listen(8888)
IOLoop.current().start()
- bind/ start:简单的多进程:
使用此接口时,不得将 anIOLoop传递给构造HTTPServer函数。 start将始终在默认单例上启动服务器IOLoop。
server = HTTPServer(app)
server.bind(8888)
server.start(0) # Forks multiple sub-processes
IOLoop.current().start()
- add_sockets:高级多进程:
接口更复杂,add_sockets但可以使用 withtornado.process.fork_processes为您在分叉发生时提供更大的灵活性。 add_sockets如果您想以除tornado.netutil.bind_sockets.
sockets = tornado.netutil.bind_sockets(8888)
tornado.process.fork_processes(0)
server = HTTPServer(app)
server.add_sockets(sockets)
IOLoop.current().start()
3.6 tornado.httpclient
tornado.httpclient — Asynchronous HTTP client
阻塞和非阻塞 HTTP 客户端接口。该模块定义了一个由两个实现共享的通用接口, simple_httpclient并且curl_httpclient. 应用程序可以直接实例化他们选择的实现类,也可以使用该模块中的AsyncHTTPClient类,该模块选择可以用该AsyncHTTPClient.configure方法覆盖的实现。默认实现是simple_httpclient,预计这将适合大多数用户的需求。
AsyncHTTPClient是一个异步非阻塞的HTTP客户端,使用AsyncHTTPClient方法需要提供回调函数callback。 HTTPClient是同步阻塞的HTTP客户端,它是完全同步的,也就是说当HTTPClient发生阻塞时,其他人是无法访问的。- 一个阻塞的 HTTP 客户端。
import tornado.httpclient
import tornado.ioloop
import tornado.options
import tornado.web
from tornado.httpclient import HTTPClient, HTTPError
import platform
if platform.system() == "Windows":
import asyncio
asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
http_client = tornado.httpclient.HTTPClient()
try:
response = http_client.fetch("http://data.live.126.net/livechannel/classifylist.json")
print(response.body)
except tornado.httpclient.HTTPError as e:
# HTTPError is raised for non-200 responses; the response
# can be found in e.response.
print("Error: " + str(e))
except Exception as e:
# Other errors are possible, such as IOError.
print("Error: " + str(e))
http_client.close()
- 运行结果如下:
- 非阻塞 HTTP 客户端。
#!/usr/bin/env python
# -*- coding:utf-8 -*-
from tornado.httpclient import AsyncHTTPClient
from tornado.ioloop import IOLoop
import platform
if platform.system() == "Windows":
import asyncio
asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
async def get_url():
http_client = AsyncHTTPClient()
try:
response = await http_client.fetch("http://img1.money.126.net/data/hs/time/today/1399001.json")
except Exception as e:
print("Error: %s" % e)
else:
print(response.body)
loop = asyncio.get_event_loop()
result = loop.run_until_complete(get_url())
loop.close()
- 运行结果如下:
另一个例子代码如下:
#!/usr/bin/env python
# -*- coding:utf-8 -*-
from tornado.httpclient import AsyncHTTPClient
from tornado.ioloop import IOLoop
import platform
if platform.system() == "Windows":
import asyncio
asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
def handle_request(response):
print(response)
if response.error:
print(response.error)
else:
print(response.body)
client = AsyncHTTPClient()
client.fetch("http://img1.money.126.net/data/hs/time/today/1399001.json", handle_request)
IOLoop.instance().start()
- 运行结果如下:
- 命令行界面
# Fetch the url and print its body
python -m tornado.httpclient http://www.baidu.com
# Just print the headers
python -m tornado.httpclient --print_headers --print_body=false http://www.baidu.com
3.7 tornado.tcpserver
Tornado有了tornado.ioloop和tornado.iostream两个模块的帮助可以实现异步Web服务器,tornado.httpserver是Tornado的Web服务器模块,该模块中实现了HTTPServer - 一个单线程HTTP服务器,其实现是基于tornado.tcpserver模块的TCPServer。
TCPServer是一个非阻塞单线程的TCP服务器,负责处理TCP协议部分的内容,并预留handle_stream抽象接口方法针对相应的应用层协议编写服务器。
(1)使用bind + start绑定开启的方式用于多进程
import tornado.tcpserver from TCPServer
import tornado.ioloop from IOLoop
server = TCPServer()
server.listen(8000)
IOLoop.current().start()
(2)使用listen监听的方式用于单进程
import tornado.tcpserver from TCPServer
import tornado.ioloop from IOLoop
server = TCPServer()
server.bind(8000)
server.starat(0) # fork派生创建多个子进程
IOLoop.current().start()
- TCPServer测试例子1:
#! /usr/bin/env python3
# -*- coding=utf-8 -*-
from tornado.tcpserver import TCPServer
from tornado.ioloop import IOLoop
from tornado.options import define, options
import platform
if platform.system() == "Windows":
import asyncio
asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
define("port", type=int, default=8888)
class Server(TCPServer):
def handle_stream(self, sockfd, client_addr):
print("client: ", client_addr)
sockfd.read_until_close(self.handle_recv)
def handle_recv(self, data):
print(data)
if __name__=="__main__":
options.parse_command_line()
server = Server()
server.listen(options.port, address="127.0.0.1")
IOLoop.instance().start()
- TCPServer测试例子2:
#! /usr/bin/env python3
# -*- coding=utf-8 -*-
from tornado.tcpserver import TCPServer
from tornado.ioloop import IOLoop
from tornado.options import define, options
from tornado import iostream, gen
import platform
if platform.system() == "Windows":
import asyncio
asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
class Server(TCPServer):
@gen.coroutine
def handle_stream(self, stream, address):
try:
while True:
msg = yield stream.read_bytes(128, partial = True)
print(msg, "from", address)
yield stream.write(msg[::-1])
if msg == "quit":
stream.close()
except iostream.StreamClosedError:
pass
if __name__ == "__main__":
server = Server()
server.listen(8888)
server.start()
IOLoop.current().start()
- TCPServer测试例子3:
import asyncio
import errno
import functools
import socket
import tornado.ioloop
from tornado.iostream import IOStream
import platform
if platform.system() == "Windows":
import asyncio
asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
async def handle_connection(connection, address):
print("handle_connection", address)
stream = IOStream(connection)
message = await stream.read_until_close()
print("message from client:", message.decode().strip())
def connection_ready(sock, fd, events):
print("connection_ready")
while True:
try:
connection, address = sock.accept()
except BlockingIOError:
return
connection.setblocking(0)
io_loop = tornado.ioloop.IOLoop.current()
io_loop.spawn_callback(handle_connection, connection, address)
print("while:", address)
async def main():
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.setblocking(0)
sock.bind(("", 8888))
sock.listen(128)
io_loop = tornado.ioloop.IOLoop.current()
callback = functools.partial(connection_ready, sock)
io_loop.add_handler(sock.fileno(), callback, io_loop.READ)
await asyncio.Event().wait()
if __name__ == "__main__":
asyncio.run(main())
- 运行结果(使用c++客户端连接TornadoTCP服务端):
(1)TornadoTCP服务端
(2)c++客户端
3.8 tornado.tcpclient
#! /usr/bin/python3
# encoding=utf-8
from tornado import gen, iostream
from tornado.tcpclient import TCPClient
from tornado.ioloop import IOLoop
import platform
if platform.system() == "Windows":
import asyncio
asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
@gen.coroutine
def Trans():
stream = yield TCPClient().connect("127.0.0.1", 8888)
try:
while True:
data = input("Enter: ")
yield stream.write( str(data).encode('utf-8') )
back = yield stream.read_bytes(20, partial = True)
msg = yield stream.read_bytes(20, partial = True)
print(back, msg)
if data == "quit":
break
except iostream.StreamClosedError:
pass
if __name__ == "__main__":
IOLoop.current().run_sync(Trans)
- 运行结果(使用c++服务端连接TornadoTCP客户端):
(1)TornadoTCP客户端
(2)c++服务端
4、扩展示例
4.1 tornado+https
要使此服务器为 SSL 流量提供服务,请发送ssl_options带有ssl.SSLContext对象的关键字参数。为了与旧版本的 Python 兼容,ssl_options还可能是该ssl.wrap_socket方法的关键字参数字典:
ssl_ctx = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
ssl_ctx.load_cert_chain(os.path.join(data_dir, "mydomain.crt"),
os.path.join(data_dir, "mydomain.key"))
HTTPServer(application, ssl_options=ssl_ctx)
- 具体测试代码如下:
#!/usr/bin/env python
# -*- coding:utf-8 -*-
import os
import ssl
from tornado.httpserver import HTTPServer
from tornado.web import Application, RequestHandler
from tornado.ioloop import IOLoop
import platform
if platform.system() == "Windows":
import asyncio
asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
class TestHandler(RequestHandler):
def get(self):
self.write("Hello, World!\n")
settings = {
"static_path" : os.path.join(os.path.dirname(__file__), "static"),
}
application = Application([
(r"/", TestHandler),
], **settings)
if __name__ == "__main__":
server = HTTPServer(application,ssl_options={
"certfile": os.path.join(os.path.abspath("."), "server.crt"),
"keyfile": os.path.join(os.path.abspath("."), "server.key"),
})
server.listen(8000)
IOLoop.instance().start()
4.2 tornado+nginx
windows下建议采用nginx + tornado方案。
使用nginx web服务器,tornado充当wsgi,tornado负责监听5000端口。
- 编写脚本test_tornado.py:
# -*- coding: utf-8 -*-
import tornado.ioloop
import tornado.web
import tornado.options
from tornado.options import options, define, parse_command_line
import platform
if platform.system() == "Windows":
import asyncio
asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
define('port', type=int, default=8080)
class MainHandler(tornado.web.RequestHandler):
def get(self):
self.write("Hello World,爱看书的小沐,2022!" + "<br>port: " + options.port)
if __name__ == "__main__":
tornado.options.parse_command_line()
app = tornado.web.Application([(r"/", MainHandler)])
http_server = tornado.httpserver.HTTPServer(app)
http_server.listen(options.port)
tornado.ioloop.IOLoop.current().start()
- 修改配置文件nginx.conf:
worker_processes 1;
events {
worker_connections 1024;
}
http {
upstream frontends {
server 127.0.0.1:8000;
server 127.0.0.1:8001;
server 127.0.0.1:8002;
server 127.0.0.1:8003;
}
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
server {
listen 80;
server_name localhost;
location ^~ /static/ {
root D:\PythonProject\django_web;
if ($query_string) {
expires max;
}
}
location ^~ /media/ {
root D:\PythonProject\django_web;
if ($query_string) {
expires max;
}
}
location = /favicon.ico {
rewrite (.*) /static/favicon.ico;
}
location = /robots.txt {
rewrite (.*) /static/robots.txt;
}
location / {
proxy_pass_header Server;
proxy_set_header Host $http_host;
proxy_redirect off;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Scheme $scheme;
proxy_pass http://frontends;
}
}
}
- (1)运行tornado服务
python test_tornado.py --port=8000
python test_tornado.py --port=8001
python test_tornado.py --port=8002
python test_tornado.py --port=8003
- (2)运行nginx.exe启动程序
cd ..
cd ..
cd nginx
start nginx
nginx.exe -s quit #停止服务
nginx.exe -s stop #停止服务
nginx.exe -s reload #重启服务
- (3)浏览器访问http://127.0.0.1
启动后在浏览器中输入http://127.0.0.1或http://localhost后,即显示nginx欢迎画面。
运行结果如下:
4.3 tornado+mysql
torndb数据库简介 在Tornado3.0版本以前提供tornado.database模块用来操作MySQL数据库,而从3.0版本开始,此模块就被独立出来,作为torndb包单独提供。 torndb只是对MySQLdb的简单封装,不支持Python 3。
MySQLdb不支持python3.x
PyMySQL支持python3.x
这里使用PyMySQL进行测试:
pip install PyMySQL
- Python测试代码如下:
#!/usr/bin/env Python
# coding=utf-8
import tornado.ioloop
import tornado.web
import tornado.options
from tornado.options import options, define, parse_command_line
import pymysql
import platform
if platform.system() == "Windows":
import asyncio
asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
define('port', type=int, default=8888)
settings = {
"template_path":"templates",
"static_path":"statics",
}
class LoginHandler(tornado.web.RequestHandler):
# def get(self):
# self.render('login.html')
def get(self):
self.write('<html><body><form action="/login" method="POST">'
'用户名称:<input type="text" name="username"><br>'
'用户密码:<input type="text" name="password"><br>'
'<input type="submit" value="登陆">'
'</form></body></html>')
def post(self, *args, **kwargs):
username = self.get_argument('username',None)
password = self.get_argument('password', None)
# 数据库连接
conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', passwd='123456', db='data_platform')
cursor = conn.cursor()
sql = "select username from t_user where username='%s' and password='%s'" %(username, password)
effect_row = cursor.execute(sql)
result = 0
if effect_row > 0:
result = cursor.fetchone()
conn.commit()
cursor.close()
conn.close()
print(effect_row, result)
if result:
# self.render('index.html', items=['登录成功!', result[0]])
self.write('<html><body>爱看书的小沐(%s),恭喜登陆成功!</body></html>' % username)
else:
# self.render('index.html', items=['登录失败!'])
self.write('<html><body>爱看书的小沐(%s),很遗憾登陆失败。</body></html>' % username)
class MainHandler(tornado.web.RequestHandler):
def get(self):
self.write("Hello World,爱看书的小沐(tornado),2022!" + "<br>port: " + str(options.port))
def make_app():
return tornado.web.Application([
(r"/", MainHandler),
(r"/login", LoginHandler),
],**settings)
if __name__ == "__main__":
tornado.options.parse_command_line()
app = make_app()
server = tornado.httpserver.HTTPServer(app)
server.listen(options.port)
tornado.ioloop.IOLoop.current().start()
- 测试结果如下:
结语
如果您觉得该方法或代码有一点点用处,可以给作者点个赞,或打赏杯咖啡;
╮( ̄▽ ̄)╭
如果您感觉方法或代码不咋地//(ㄒoㄒ)//,就在评论处留言,作者继续改进;
o_O???
如果您需要相关功能的代码定制化开发,可以留言私信作者;
(✿◡‿◡)
感谢各位童鞋们的支持!
( ´ ▽´ )ノ ( ´ ▽´)っ!!!