werkeug的WSGI服务器解析
Posted wodeboke-y
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了werkeug的WSGI服务器解析相关的知识,希望对你有一定的参考价值。
werkeug的WSGI服务器解析
1. WSGI
1.1. wsgi与flask
flask默认的wsgi引用自wekurg
声明app:FLASK对象
app.run()
run_simple(host, port, self, **options)
引用自werkzurg.serving
host 主机
port 监听端口
self app本身
run_simple(host, port, self, **options)
host 主机
port 监听端口
self app本身
run_simple引用inner()
做了两件事,声明srv,运行它
srv = make_server(hostname, port, application, threaded,
processes, request_handler,
passthrough_errors, ssl_context,
fd=fd)
if fd is None:
srv.serve_forever()
看一下make_server()
它最终执行return BaseWSGIServer(host, port, app, request_handler,
passthrough_errors, ssl_context, fd=fd)
那么
srv = BaseWSGIServer()
class BaseWSGIServer(HTTPServer, object):
"""Simple single-threaded, single-process WSGI server."""
1.2. WSGI server
是默认的server是BaseWSGIServer()
1.2.1. 初始化
初始化中执行了
HTTPServer.__init__(self, get_sockaddr(host, int(port),self.address_family), handler)
在这一过程中
创建socket,绑定,listen
核心属性释义:
self.socket
host,
port
self.server_address = server_address = get_sockaddr(host, int(port),self.address_family)
self.RequestHandlerClass = WSGIRequestHandler
至此,server对象创建完成并对端口进行监听。
中间还有一些上下文,ssl等处理,略过。
下面的一般就是构建一个死循环,处理请求,等待。。。
1.2.2. serve_forever
上面BaseWSGIServer()已初始化完成,返回flask调用serve_forever
它实质是调用httpserver.serve_forever(self)
先看下BaseWSGIServer()
BaseWSGIServer():
def serve_forever(self):
self.shutdown_signal = False
try:
HTTPServer.serve_forever(self)
except KeyboardInterrupt:
pass
finally:
self.server_close()
继续向下,HTTPServer:
import socketserver
from http.server import HTTPServer, BaseHTTPRequestHandler
它基本继承于socketserver.TCPServer
class HTTPServer(socketserver.TCPServer):
socketserver.TCPServer基本继承于BaseServer
class TCPServer(BaseServer):
找到serve_forever
def serve_forever(self, poll_interval=0.5):
"""Handle one request at a time until shutdown.
Polls for shutdown every poll_interval seconds. Ignores
self.timeout. If you need to do periodic tasks, do them in
another thread.
"""
self.__is_shut_down.clear()
try:
# XXX: Consider using another file descriptor or connecting to the
# socket to wake this up instead of polling. Polling reduces our
# responsiveness to a shutdown request and wastes cpu at all other
# times.
with _ServerSelector() as selector:
selector.register(self, selectors.EVENT_READ)
while not self.__shutdown_request:
ready = selector.select(poll_interval)
if ready:
self._handle_request_noblock()
self.service_actions()
finally:
self.__shutdown_request = False
self.__is_shut_down.set()
做了以下事情:
- 在selector上注册监听及处理触发
selector.register(self, selectors.EVENT_READ)
ready = selector.select(poll_interval)
if ready:
self._handle_request_noblock()
- 如果监听被触发了,调用self._handle_request_noblock()
至此,服务算是跑起来了。
1.3. 请求处理
从socket开始,上面讲过触发监听后调用BaseWSGIServer() 的self._handle_request_noblock()
def _handle_request_noblock(self):
"""Handle one request, without blocking.
I assume that selector.select() has returned that the socket is
readable before this function was called, so there should be no risk of
blocking in get_request().
"""
try:
request, client_address = self.get_request()
# get_request实质是con, addr = self.socket.accept()
except OSError:
return
if self.verify_request(request, client_address):
try:
self.process_request(request, client_address)
except Exception:
self.handle_error(request, client_address)
self.shutdown_request(request)
except:
self.shutdown_request(request)
raise
else:
self.shutdown_request(request)
核心句是self.process_request(request, client_address)
最终是调用self.RequestHandlerClass(request, client_address, self)
上面讲过self.RequestHandlerClass = WSGIRequestHandler
到这里是监听到了一个客户端发起了连接,下面进入到连接及请示处理。
1.4. WSGIRequestHandler
先看下定义及初始化
class WSGIRequestHandler(BaseHTTPRequestHandler, object):
"""A request handler that implements WSGI dispatching."""
class BaseHTTPRequestHandler(socketserver.StreamRequestHandler):
class StreamRequestHandler(BaseRequestHandler):
class BaseRequestHandler:
"""Base class for request handler classes.
def __init__(self, request, client_address, server):
self.request = request
self.client_address = client_address
self.server = server
self.setup()
try:
self.handle()
finally:
self.finish()
链条很长,在初始化时执行self.handle()
def handle(self):
"""Handles a request ignoring dropped connections."""
rv = None
try:
rv = BaseHTTPRequestHandler.handle(self)
except (socket.error, socket.timeout) as e:
self.connection_dropped(e)
except Exception:
if self.server.ssl_context is None or not is_ssl_error():
raise
if self.server.shutdown_signal:
self.initiate_shutdown()
return rv
def handle_one_request(self):
"""Handle a single HTTP request."""
self.raw_requestline = self.rfile.readline()
if not self.raw_requestline:
self.close_connection = 1
elif self.parse_request():
return self.run_wsgi()
后面代码比较长,简单点说
self.handle_one_request()的任务:
处理本次连接,收取报文,把socket recv的数据第一行(请求头)放到self.raw_requestline
然后调用self.parse_request(),负责把报文解析成http报文,提取出请求方法(get/post)
然后执行self.run_wsgi(),在其中执行下列语句:
self.environ = environ = self.make_environ()
# 生成上下文
最后execute(self.server.app)
# 交由app处理
execute定义:
def execute(app):
application_iter = app(environ, start_response)
try:
for data in application_iter:
write(data)
if not headers_sent:
write(b‘‘)
finally:
if hasattr(application_iter, ‘close‘):
application_iter.close()
application_iter = None
释义:application_iter = app(environ, start_response)等于
Flask().__call__(environ, start_response)
然后flask返回数据,wsgi写入socket。
1.5. flask
flask返回数据
核心是上下文,路由,执行view函数
最后由下面一句调用view function
return self.view_functions[rule.endpoint](**req.view_args)
2. 总结
WSGI主要两个任务:
- 创建服务,监听端口
- 处理连接,ip报文处理成http报文,转给app获取response,把response写入连接
据此有两大类class
第一类:服务
class BaseWSGIServer(HTTPServer, object):
class HTTPServer(socketserver.TCPServer):
它基本继承于socketserver.TCPServer
class TCPServer(BaseServer):
socketserver.TCPServer基本继承于BaseServer
分别是顶层应用,HTTP,TCP,socket四个层面的功能类。
第二类:请求处理
WSGIRequestHandler
class WSGIRequestHandler(BaseHTTPRequestHandler, object):
"""A request handler that implements WSGI dispatching."""
class BaseHTTPRequestHandler(socketserver.StreamRequestHandler):
类似的,分三层,WSGI,HTTP,SOCKET。
以上是关于werkeug的WSGI服务器解析的主要内容,如果未能解决你的问题,请参考以下文章