原地址: 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 的服務器端發生了什麼呢?