Interpretation of Flask source code (1) and flask source code

Source: Internet
Author: User

Interpretation of Flask source code (1) and flask source code

FlaskIs a lightweight Web application framework written in Python. Flask is only a bridge between Werkezug and Jinja2. The former implements a suitable WSGI application and the latter processes the template. Of course, Flask is also bound to some common standard library packages, such as logging. Everything else is done by extension. I will track the running of a simple FlaskApp and see how request and response are implemented. The following is a simple flask app code that can be accessed by a browser.

#!/usr/bin/env python# encoding: utf-8from flask import Flaskapp = Flask(__name__)@app.route('/')def index():    import pdb;pdb.set_trace()    return '

Capture stack calls through pdb.

/Home/steinliber/flask-source-code/route/a. py (18) <module> ()
-> App. run ()
/Home/steinliber/flask-source-code/env/local/lib/python2.7/site-packages/flask/app. py (772) run ()
-> Run_simple (host, port, self, ** options)
/Home/steinliber/flask-source-code/env/local/lib/python2.7/site-packages/werkzeug/serving. py (692) run_simple ()
-> Inner ()
/Home/steinliber/flask-source-code/env/local/lib/python2.7/site-packages/werkzeug/serving. py (657) inner ()
-> Srv. serve_forever ()
/Home/steinliber/flask-source-code/env/local/lib/python2.7/site-packages/werkzeug/serving. py (497) serve_forever ()
-> HTTPServer. serve_forever (self)
This is the function called to start the flask server. You can see that because the app is a Flask instance, the app is called. run () will call run () in the Flask class, while the run () method calls run_simple () of werkzeug simply by setting the default value for the host and port ()

Run_simple () function in werkzeug

def run_simple(hostname, port, application, use_reloader=False,               use_debugger=False, use_evalex=True,               extra_files=None, reloader_interval=1,               reloader_type='auto', threaded=False,               processes=1, request_handler=None, static_files=None,               passthrough_errors=False, ssl_context=None):    if use_debugger:        from werkzeug.debug import DebuggedApplication        application = DebuggedApplication(application, use_evalex)    if static_files:        from werkzeug.wsgi import SharedDataMiddleware        application = SharedDataMiddleware(application, static_files)    def log_startup(sock):        display_hostname = hostname not in ('', '*') and hostname or 'localhost'        if ':' in display_hostname:            display_hostname = '[%s]' % display_hostname        quit_msg = '(Press CTRL+C to quit)'        port = sock.getsockname()[1]        _log('info', ' * Running on %s://%s:%d/ %s',             ssl_context is None and 'http' or 'https',             display_hostname, port, quit_msg)    def inner():        try:            fd = int(os.environ['WERKZEUG_SERVER_FD'])        except (LookupError, ValueError):            fd = None        srv = make_server(hostname, port, application, threaded,                          processes, request_handler,                          passthrough_errors, ssl_context,                          fd=fd)        if fd is None:            log_startup(srv.socket)        srv.serve_forever()
    if use_reloader:
        # If we're not running already in the subprocess that is the
        # reloader we want to open up a socket early to make sure the
        # port is actually available.
        if os.environ.get('WERKZEUG_RUN_MAIN') != 'true':
            if port == 0 and not can_open_by_fd:
                raise ValueError('Cannot bind to a random port with enabled '
                                 'reloader if the Python interpreter does '
                                 'not support socket opening by fd.')

            # Create and destroy a socket so that any exceptions are
            # raised before we spawn a separate Python interpreter and
            # lose this ability.
            address_family = select_ip_version(hostname, port)
            s = socket.socket(address_family, socket.SOCK_STREAM)
            s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
            s.bind((hostname, port))
            if hasattr(s, 'set_inheritable'):
                s.set_inheritable(True)

            # If we can open the socket by file descriptor, then we can just
            # reuse this one and our socket will survive the restarts.
            if can_open_by_fd:
                os.environ['WERKZEUG_SERVER_FD'] = str(s.fileno())
                s.listen(LISTEN_QUEUE)
                log_startup(s)
            else:
                s.close()

        from ._reloader import run_with_reloader
        run_with_reloader(inner, extra_files, reloader_interval,
                          reloader_type)
    else:
        inner()

This is the main function of run_simple (). The first two judgment statements are packaging the debug mode and static files. ShareDataMiddleware is a middleware. Here, it serves to convert the file into a Response form acceptable to the server.

Use_reloader is used to determine whether to restart the server when the app code changes. If it is True, a socket is established. can_open_by_fd is determined by the fromfd feature in the socket, if you can store fd in environment variables for reuse after restart, the socket starts to listen, and then calls run_with_reloader, which also accepts the inner function. we can see that when use_reloader is True or not, the inner function inside the function is called. In the inner function, the key WERKZEUG_SERVER_FD in the Environment stores reusable sockets, if not, set it to None and then call the make_server function. Select the appropriate server based on the process and threads parameters. After obtaining the Server Object, call the run_forever method, the server is started ., Werkzeug provides multiple optional servers. Here is a basic Single-threaded, single-process server.

class BaseWSGIServer(HTTPServer, object):    """Simple single-threaded, single-process WSGI server."""    multithread = False    multiprocess = False    request_queue_size = LISTEN_QUEUE    def __init__(self, host, port, app, handler=None,                 passthrough_errors=False, ssl_context=None, fd=None):        if handler is None:            handler = WSGIRequestHandler        self.address_family = select_ip_version(host, port)        if fd is not None:            real_sock = socket.fromfd(fd, self.address_family,                                      socket.SOCK_STREAM)            port = 0        HTTPServer.__init__(self, (host, int(port)), handler)        self.app = app        self.passthrough_errors = passthrough_errors        self.shutdown_signal = False        self.host = host        self.port = port        # Patch in the original socket.        if fd is not None:            self.socket.close()            self.socket = real_sock            self.server_address = self.socket.getsockname()        if ssl_context is not None:            if isinstance(ssl_context, tuple):                ssl_context = load_ssl_context(*ssl_context)            if ssl_context == 'adhoc':                ssl_context = generate_adhoc_ssl_context()            # If we are on Python 2 the return value from socket.fromfd            # is an internal socket object but what we need for ssl wrap            # is the wrapper around it :(            sock = self.socket            if PY2 and not isinstance(sock, socket.socket):                sock = socket.socket(sock.family, sock.type, sock.proto, sock)            self.socket = ssl_context.wrap_socket(sock, server_side=True)            self.ssl_context = ssl_context        else:            self.ssl_context = None    def log(self, type, message, *args):        _log(type, message, *args)    def serve_forever(self):        self.shutdown_signal = False        try:            HTTPServer.serve_forever(self)        except KeyboardInterrupt:            pass        finally:            self.server_close()    def handle_error(self, request, client_address):        if self.passthrough_errors:            raise        return HTTPServer.handle_error(self, request, client_address)    def get_request(self):        con, info = self.socket.accept()        return con, info

This server inherits the basic HTTPServer, HTTPServer can receive data at the specified port and process the results passed to RequestHandlerClass, specific can see the official documentation https://docs.python.org/2/library/basehttpserver.html

In the code, request_queue_size specifies the maximum number of connections in the Request queue. In the _ init _ function, handler is the request processor. If the parameter is provided, it is set to the default value, the available socket is obtained. ssl_context is mainly used to help implement SSL. In addition, the HTTPServer method is simply rewritten. In serve_forever, The HTTPServer method is called to implement server functions.

In summary, flask is the implementation of a basic server. In this example, you can see how to add multiple functions to a simple server, such as SSL, socket multiplexing, and server overloading, the next step is the implementation of reloader and SSL.

 

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.