📜  第 1030 行,在 run_simple s.bind(server_address) (1)

📅  最后修改于: 2023-12-03 15:11:28.415000             🧑  作者: Mango

介绍

本文将会介绍在 Python 中使用 run_simple 启动 Flask 应用时的绑定(bind)过程。在第 1030 行的 s.bind(server_address),是在绑定服务器地址和端口,让服务器监听指定的地址和端口,从而开始接受客户端的请求。

代码片段
def run_simple(hostname, port, application, use_reloader=False, use_debugger=False,
               use_evalex=True, extra_files=None, reloader_interval=1, threaded=False,
               processes=1, request_handler=None, static_files=None):
    """Start an application using a built-in server."""
    if request_handler is None:
        request_handler = WSGIRequestHandler
    if ':' in hostname:
        hostname = '[{}]'.format(hostname)
    family = None
    for res in socket.getaddrinfo(hostname, port, socket.AF_UNSPEC,
                                  socket.SOCK_STREAM, socket.IPPROTO_TCP):
        family, socktype, proto, _, _ = res
        try:
            s = socket.socket(family, socktype, proto)
            s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
            if hasattr(socket, 'SO_REUSEPORT'):
                s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1)
        except socket.error as e:
            s = None
            continue
        try:
            s.bind((hostname, port))
            break
        except socket.error as e:
            s.close()
            s = None
            continue

    if s is None:
        raise ConnectionError('Could not bind to %s:%s: %s' % (hostname, port, e))

    server_address = (hostname, port)
    try:
        handler_class = request_handler
        httpd = handler_class.get_server(application, server_address, log=app.logger, static_files=static_files)
    except socket.error as e:
        raise ConnectionError('Unable to start server: %s' % e)

    display_hostname = hostname
    if display_hostname.startswith('[') and display_hostname.endswith(']'):
        display_hostname = display_hostname[1:-1]

    protocol = 'https' if httpd.socket_context else 'http'
    app.logger.info(' * Running on %s://%s:%d/ (Press CTRL+C to quit)', protocol, display_hostname, port)

    if use_reloader:
        # Remove pydevd_tracing.set_trace function from sys.settrace, which is considered as a side-effect
        # by the reloader.
        _cleanup()

        if os.environ.get('WERKZEUG_RUN_MAIN') == 'true':
            # Disable reloader for subprocesses
            use_reloader = False
        else:
            args = sys.argv[:]
            if "--extra-files" in args:
                index = args.index("--extra-files")
                extra_files = args[index + 1]
                use_reloader = True

            if use_debugger:
                trace = lambda *x: None # noqa: E731
            else:
                trace = _trace
            #重要代码片段
            reloader = Reloader(extra_files, reloader_interval, (use_debugger, use_evalex), not threaded, trace)
            reloader.run_with_reloader(main_loop, extra_files, reloader_interval, [s], request_handler, fd=fd)

            return

    # Serve requests until process is killed
    httpd.serve_forever()
解析

首先,我们需要使用 socket 模块来创建 TCP 套接字,使用 socket.socket(family, socktype, proto) 来创建一个套接字,其中 family 是地址族(如 AF_INETAF_INET6),socktype 是套接字类型(如 SOCK_STREAMSOCK_DGRAM),proto 是协议类型(如 IPPROTO_TCPIPPROTO_UDP)。接着,设置 SO_REUSEADDR 和 SO_REUSEPORT 选项,以便服务器在关闭后可以立即重启。然后,使用 s.bind((hostname, port)) 来将套接字绑定到服务器地址和端口。

需要注意的是,如果绑定失败,则会尝试使用其他地址和端口进行绑定,直到成功为止。如果最终无法成功绑定,则会抛出 ConnectionError 异常并提示相关信息。

最后,启动服务器,使其在指定的地址和端口上侦听来自客户端的请求,并提供相应的响应。