原地址: http://cizixs.com/2014/11/09/...
要很好地理解下面的代码,最好有必定的 socket 编程基础,了解 socket 的基本概念和流程。python
wsgiref 是 PEP 333 定义的 wsgi 规范的范例实现,里面的功能包括了:编程
咱们先看一个简单的代码实例,而后跟着例子去理解源码:服务器
# pep333 定义的程序端可调用对象 def hello_world_app(environ, start_response): status = '200 OK' # HTTP Status headers = [('Content-type', 'text/plain')] # HTTP Headers start_response(status, headers) # The returned object is going to be printed return ["Hello World"]
from app import hello_world_app from wsgiref.simple_server import make_server httpd = make_server('', 8000, hello_world_app) print "Serving on port 8000..." # Serve until process is killed httpd.serve_forever()
而后执行 python server.py
启动 sever,用 curl 发送一个请求 curl -i http://localhost:8000/
,会有如下输出:app
HTTP/1.0 200 OK Date: Sat, 08 Nov 2014 09:08:05 GMT Server: WSGIServer/0.1 Python/2.7.3 Content-type: text/plain Content-Length: 12 Hello World
server 的终端会有一条记录:curl
Serving on port 8000... localhost - - [08/Nov/2014 09:08:05] "GET / HTTP/1.1" 200 12
你能够使用 python -c 'import wsgiref; help(wsgiref)'
查看 wsgiref 库的路径和简介等信息,wsgiref 文件夹的结构以下:socket
wsgiref |-- handlers.py # 核心代码,负责 wsgi 程序的处理 |-- headers.py # 头部处理的代码 |-- __init__.py # |-- simple_server.py # 简单的 wsgi HTTP 服务器实现 |-- util.py # 帮助函数 `-- validate.py # wsgi 格式检查和校验
主要的代码结构以下图所示:ide
咱们先看一下 make_server
是怎么启动一个 wsgi 服务器的:函数
def make_server(host, port, app, server_class=WSGIServer, handler_class=WSGIRequestHandler): server = server_class((host, port), handler_class) server.set_app(app) return server
这个函数作的事情就是:监听在本地的端口上,接受来自客户端的请求,经过 WSGIServer 和 WSGIRequestHandler 处理后,把请求交给程序的的可调用对象 app,而后返回 app 的结果给客户端。源码分析
这里有两个重要的类:WSGIServer 和 WSGIRequestHandler。下面分别看一下它们的代码和执行的功能。url
class WSGIServer(HTTPServer): """BaseHTTPServer that implements the Python WSGI protocol""" application = None def server_bind(self): """Override server_bind to store the server name.""" HTTPServer.server_bind(self) self.setup_environ() def setup_environ(self): # Set up base environment env = self.base_environ = {} env['SERVER_NAME'] = self.server_name env['GATEWAY_INTERFACE'] = 'CGI/1.1' env['SERVER_PORT'] = str(self.server_port) env['REMOTE_HOST']='' env['CONTENT_LENGTH']='' env['SCRIPT_NAME'] = '' def get_app(self): return self.application def set_app(self,application): self.application = application
WSGIServer 在原来的 HTTPServer 上面封装了一层,在原来的 HTTPServer 的基础上又额外作了下面的事情:
class WSGIRequestHandler(BaseHTTPRequestHandler): server_version = "WSGIServer/" + __version__ def get_environ(self): env = self.server.base_environ.copy() env['SERVER_PROTOCOL'] = self.request_version env['REQUEST_METHOD'] = self.command if '?' in self.path: path,query = self.path.split('?',1) else: path,query = self.path,'' env['PATH_INFO'] = urllib.unquote(path) env['QUERY_STRING'] = query host = self.address_string() if host != self.client_address[0]: env['REMOTE_HOST'] = host env['REMOTE_ADDR'] = self.client_address[0] if self.headers.typeheader is None: env['CONTENT_TYPE'] = self.headers.type else: env['CONTENT_TYPE'] = self.headers.typeheader length = self.headers.getheader('content-length') if length: env['CONTENT_LENGTH'] = length for h in self.headers.headers: k,v = h.split(':',1) k=k.replace('-','_').upper(); v=v.strip() if k in env: continue # skip content length, type,etc. if 'HTTP_'+k in env: env['HTTP_'+k] += ','+v # comma-separate multiple headers else: env['HTTP_'+k] = v return env def get_stderr(self): return sys.stderr def handle(self): """Handle a single HTTP request""" self.raw_requestline = self.rfile.readline() if not self.parse_request(): # An error code has been sent, just exit return handler = ServerHandler( self.rfile, self.wfile, self.get_stderr(), self.get_environ() ) handler.request_handler = self # backpointer for logging handler.run(self.server.get_app())
这个类从名字就能知道它的功能——处理客户端的 HTTP 请求,它也是在原来处理 http 请求的BaseHTTPRequestHandler 类上添加了 wsgi 规范相关的内容。
这个文件主要是 wsgi server 的处理过程,定义 start_response、调用 wsgi app 、处理 content-length 等等。
服务器端启动服务,等到客户端输入 curl -i http://localhost:8000/
命令,摁下回车键,看到终端上的输出,整个过程当中,wsgi 的服务器端发生了什么呢?