tornado一:一个基本的tornado服务器
一、一个基本的tornado服务器
#coding=utf-8 import tornado.web """tornado的基础web框架模块""" import tornado.ioloop """tornado的核心io循环模块,封装了linux的epoll和bsd的kqueue""" #类比django中的视图,一个业务处理类 class IndexHandler(tornado.web.RequestHandler): # 这里重写了get方法,处理get请求的类;不能处理其它请求,如post def get(self, *args, **kwargs): # get对应http请求的方法 # self.write给浏览器响应信息 self.write("this is return text") if __name__ == '__main__': # Application:是tornado web框架的核心应用类,是与服务器对应的接口(里面保存了路由映射表) # 用Applications类实例化一个app,然后由app实例调用Application的方法 app = tornado.web.Application([ (r'/', IndexHandler) ]) #1. app实例的listen方法:用来创建一个http服务器,并绑定监听端口 # 注意:此时服务器并没有开启监听,app.listen相当于tcp服务器的bind app.listen(8000) """IOLoop.current():返回当前线程的IOLoop实例 IOLoop.start():启动IOLoop实例的I/O循环(这里是网络连接I/O),同时开启监听。 监听:start创建linux epoll服务器监听套接字,由linux epoll服务器负责此套接字的监听 linux服务器:如果此服务器套接字有连接,linux epoll服务器为每个客户端创建一个响应的socket; IOLoop实例循环:循环询问linux epoll服务器的监听套接字,是否有此套接字的连接请求; app路由:如果IOLoop实例循环得到从linux服务器得到请求信号,交给Application实例app处理,app根据请求地址,由不同的路由调用不同的Handler。 Handler:Handler异步返回数据给linux为客户端创建的响应套接字,一个客户端请求对应一个响应套接字""" tornado.ioloop.IOLoop.current().start()
app.listen自动创建了http服务器,如果要手动创建httpserver呢?
二、手动创建http服务器
#coding=utf-8 import tornado.web import tornado.ioloop class IndexHandler(tornado.web.RequestHandler): def get(self, *args, **kwargs): self.write("this is return text") if __name__ == '__main__': app = tornado.web.Application([ (r'/', IndexHandler) ]) import tornado.httpserver # 参数app用于告诉http服务器的路由 # 创建http服务器,即实例化HTTPServer对象 httpServer = tornado.httpserver.HTTPServer(app) # 绑定端口 httpServer.listen(8000) tornado.ioloop.IOLoop.current().start()
以上,无论是app.listen(port)还是httpServer.listen(port),都是单进程http服务器。
因此,tornado使用listen绑定端口时,默认是启动单进程服务器。
如果开启多进程http服务器呢?不使用listen绑定端口,使用bind绑定端口则可以使用start方法定义多个进程
三、创建简单的多进程http服务器
#coding=utf-8 import tornado.web import tornado.ioloop class IndexHandler(tornado.web.RequestHandler): def get(self, *args, **kwargs): self.write("this is return text") if __name__ == '__main__': app = tornado.web.Application([ (r'/', IndexHandler) ]) import tornado.httpserver # 参数app用于告诉http服务器的路由 # 创建http服务器,即实例化HTTPServer对象 httpServer = tornado.httpserver.HTTPServer(app) # 绑定端口 httpServer.bind(8000) # 指明多进程http服务器的进程数量 httpServer.start(num_processes=32) # num_process没有值时:默认开启1个进程;num_process的值大于1时,为多个子进程; # num_process的值为None或小于等于0时,开启服务器硬件cpu个数的子进程
tornado.ioloop.IOLoop.current().start()
四、 创建高级多进程httpserver
方式:绑定socket
add_sockets 接口更加复杂, 但是,当fork发生的时候,它可以与 tornado.process.fork_processes 一起使用来提供更好的灵活性。 如果你想使用其他的方法,而不是 tornado.netutil.bind_sockets , 来创建监听socket, add_sockets 也可以被用在单进程server中。
在 4.0 版更改: 增加了 decompress_request, chunk_size, max_header_size, idle_connection_timeout, body_timeout, max_body_size 参数。支持 HTTPServerConnectionDelegate 实例化为 request_callback 。
在 4.1 版更改: HTTPServerConnectionDelegate.start_request 现在需要传入两个参数来调用 (server_conn, request_conn) (根据文档内容)而不是一个 (request_conn).
在 4.2 版更改: HTTPServer 现在是 tornado.util.Configurable 的一个子类。
#coding=utf-8 import tornado.web import tornado.ioloop class IndexHandler(tornado.web.RequestHandler): def get(self, *args, **kwargs): self.write("this is return text") if __name__ == '__main__': app = tornado.web.Application([ (r'/', IndexHandler) ]) import tornado.httpserver
# 1.首先是调用tornado.netutil.bind_sockets来创建一个socket(或一个socket列表)
sockets = tornado.netutil.bind_sockets( port, address=BIND_IP, family=socket.AF_INET)
# 2.创建多个子进程
tornado.process.fork_processes(100)
# 3.创建http_server http_server = tornado.httpserver.HTTPServer(app)
# 4.监听socket http_server.add_sockets(sockets) tornado.ioloop.IOLoop.current().start()
上面的tornado多进程的处理流程是先创建 socket, 然后再 fork 子进程, 这样所有的子进程实际都监听 一个(或多个)文件描述符, 也就是都在监听同样的 socket.
当连接过来所有的子进程都会收到可读事件, 这时候所有的子进程都会跳到 accept_handler 回调函数, 尝试建立连接.
一旦其中一个子进程成功的建立了连接, 当其他子进程再尝试建立这个连接的时候就会触发EWOULDBLOCK(或 EAGAIN) 错误. 这时候回调函数判断是这个错误则返回函数不做处理.
当成功建立连接的子进程还在处理这个连接的时候又过来一个连接, 这时候就会有另外一个 子进程接手这个连接.
Tornado 就是通过这样一种机制, 利用多进程提升效率, 由于连接只能由一个子进程成功创建, 同一个请求也就不会被多个子进程处理.
五、总结:
1).app.listen,只能在单进程模式中使用
2).httpServer.listern,只能在单进程中使用
3).httpServer.bind()+httpServer.start(),多进程模式
4).创建sockets + fork子进程 + httpServer.add_sockets(刚创建的sockets),多进程模式
但是tornado不建议使用第3种和第4种方式一次性启动多进程;而是手动启动多个tornado实例,并且还能绑定不同的端口
因为1.第3种方式创建的多进程,都是子进程,每个子进程都会从父进程中复制一份IOLoop的实例,
如果在创建之进程前修改了IOLoop,会影响所有的子进程;
2.所有的进程都是由一个命令启动的,无法做到在不停止服务的情况下修改代码。如果只想修改一个进程里的代码,只能停止父进程,
则停止了所有子进程,所有子进程都会受到影响。
所有进程共享一个端口,想要分别监控很困难。
因此实际开发中,都是创建单进程服务器;然后手动启动多个服务器进程或者使用superviser手动管理多个http服务进程。
posted on 2018-07-22 22:58 myworldworld 阅读(842) 评论(0) 收藏 举报
浙公网安备 33010602011771号