一、前言
前面在Flask学习-Flask基础之WSGI中提到了WerkZeug,我们知道,WerkZeug是一个支持WSGI协议的Server,其实还有很多其他支持WSGI协议的Server。http://wsgi.readthedocs.io/en/latest/servers.html,这里可以看到有uwsgi、werkzeug.serving、wsgiref、python-fastcgi等等几十个。wsgiref是官方给出的一个实现了WSGI标准用于演示用的简单Python内置库,它实现了一个简单的WSGI Server和WSGI Application(在simple_server模块中),主要分为五个模块:simple_server, util, headers, handlers, validate。 wsgiref源码地址:https://pypi.python.org/pypi/wsgiref。通过学习Wsgiref,我相信能够更加清晰的了解Web框架的实现。
二、测试
wsgiref 是 PEP 333 定义的 wsgi 规范的范例实现,里面的功能包括了:
- 操作 wsgi 的环境变量
- 应答头部的处理
- 实现简单的 HTTP server
- 简单的对程序端和服务器端校验函数
由于simple_server中已经实现了一个简单的WSGI Server和WSGI Application,我们只要直接运行就可以了。
simple_server.py:
if __name__ == '__main__':
httpd = make_server('', 8000, demo_app)
sa = httpd.socket.getsockname()
print "Serving HTTP on", sa[0], "port", sa[1], "..."
import webbrowser
webbrowser.open('http://localhost:8000/xyz?abc')
httpd.handle_request() # serve one request, then exit
httpd.server_close()
然后将app运行起来后,结果如下:
三、过程分析
1、Server端启动流程
make_server('localhost', 8000, application)
先查看make_server在wsgiref中的定义:
def make_server(host, port, app, server_class=WSGIServer, handler_class=WSGIRequestHandler):
"""Create a new WSGI server listening on `host` and `port` for `app`"""
# -> HTTPServer.__init__
# -> TCPServer.__init__
# -> TCPServer.server_bind # -> TCPServer.socket.bind # -> TCPServer.server_activate # -> TCPServer.socket.listen
server = server_class((host, port), handler_class)
server.set_app(app)
return server
虽然代码只有三行,但是可以看出生成一个 server 都需要些什么:
- (host, port):主机名和端口号
- handler_class:用于处理请求的handler类
- app 服务器程序在处理时,一定会调用我们之前写好的应用程序,这样他们才能配合起来为客户端面服务,所以,你看到了那个
set_app
调用。
另外,在注释部分,你可以看到那代码背后都发生了什么。
生成 server 实例时,默认的 server_class 是 WSGIServer,它是HTTPServer的子类,后者又是TCPServer的子类,TCPServer又是BaseServer的子类。所以初始化 server 时,会沿着类的继承关系执行下去,最终,生成 server 实例的过程,其实是最底层的 TCPServer 在初始化时,完成了对socket的bind和listen。
后面的 set_app 设置了 app,它会在 handler_class (默认为WSGIRequestHandler)的handle函数中被取出来,然后交给 handler 的 run 函数运行。过程如下:
上图可以看出函数之间的调用关系,也可以看出 make_server 到 使用 socket 监听用户请求的过程。至此,Server端已经起来了。
2、Client端请求过程
httpd.handle_request()
整个过程可以看出,HTTP建立于TCP之上。
BaseServer
最需要注意的是在构造的时候设置了请求处理类RequestHandlerClass
。
class BaseServer:
def __init__(self, server_address, RequestHandlerClass):
"""Constructor. May be extended, do not override."""
self.server_address = server_address
self.RequestHandlerClass = RequestHandlerClass
self.__is_shut_down = threading.Event()
self.__shutdown_request = False
流程走到TCPServer.handle_request,过程如下:
- 首先一个连接进来,
BaseServer
监听到连接,调用self._handle_request_noblock()
处理 self._handle_request_noblock()
最终找到finish_request方法finish_request
方法实例化请求处理类RequestHandlerClass
RequestHandlerClass是由调用make_server()时传入的handler_class
def make_server( host, port, app, server_class=WSGIServer, handler_class=WSGIRequestHandler ): """Create a new WSGI server listening on `host` and `port` for `app`""" server = server_class((host, port), handler_class) #WSGIServer(server_address, RequestHandlerClass)
server.set_app(app) return server