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()

做了以下事情:

  1. 在selector上注册监听及处理触发

selector.register(self, selectors.EVENT_READ)

 

ready = selector.select(poll_interval)

if ready:

    self._handle_request_noblock()

  1. 如果监听被触发了,调用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主要两个任务:

  1. 创建服务,监听端口
  2. 处理连接,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服务器解析的主要内容,如果未能解决你的问题,请参考以下文章

CGI FastCGI WSGI 解析

python WSGI框架详解

WSGI&ASGI

WSGI&ASGI

nginx, flask, wsgi

python学习笔记_WSGI接口