werkeug的WSGI服務器解析

 werkeug的WSGI服務器解析

 

1.      WSGI

1.1.    wsgi與flask

flask默認的wsgi引用自wekurgflask

 

聲明app:FLASK對象服務器

app.run()app

run_simple(host, port, self, **options)socket

引用自werkzurg.servingide

host 主機函數

port 監聽端口post

self app自己this

run_simple(host, port, self, **options)spa

       host 主機server

       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。

相關文章
相關標籤/搜索