Created
November 7, 2017 13:10
-
-
Save polebug/054c32c3104390c83b49e2279f1a3131 to your computer and use it in GitHub Desktop.
WSGI server 基本实现
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
# -*- coding: utf-8 -*- | |
import socket | |
import StringIO | |
import sys | |
class WSGIServer(object): | |
address_family = socket.AF_INET | |
socket_type = socket.SOCK_STREAM | |
request_queue_size = 1 | |
def __init__(self, server_address): | |
# 创建socket,利用socket获取客户端的请求 | |
self.listen_socket = listen_socket = socket.socket(self.address_family, self.socket_type) | |
# 设置socket的工作模式 | |
listen_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) | |
# 绑定socket地址 | |
listen_socket.bind(server_address) | |
# socket active, 监听文件描述符 | |
listen_socket.listen(self.request_queue_size) | |
# 获得serve的host name和port | |
host, port = self.listen_socket.getsockname()[:2] | |
self.server_name = socket.getfqdn(host) | |
self.server_port = port | |
self.headers_set = [] | |
def set_app(self, application): | |
#加载一个 application | |
self.application = application | |
def serve_forever(self): | |
#启动 WSGI server服务,不停的监听并获取socket数据 | |
listen_socket = self.listen_socket | |
while True: | |
self.client_connection, client_address = listen_socket.accept() #接受客户端请求 | |
#处理请求 | |
self.handle_one_request() | |
def handle_one_request(self): | |
#处理请求 | |
self.request_data = request_data = self.client_connection.recv(1024) | |
#对数据包进行解析 | |
self.parse_request(request_data) | |
#创建 environ,给应用提供环境信息 | |
env = self.get_environ() | |
#使用 environ,start_response 作为参数,调用 application | |
result = self.application(env, self.start_response) | |
#解析请求后,关闭 socket 端口,将数据返回至客户端 | |
self.finish_response(result) | |
def parse_request(self, data): | |
#对数据包进行解析 | |
format_data = data.splitlines() | |
if len(format_data): | |
request_line = data.splitlines()[0] | |
request_line = request_line.rstrip('\r\n') | |
(self.request_method, self.path, self.request_version) = request_line.split() ## ['GET', '/', 'HTTP/1.1'] | |
def get_environ(self): | |
#给应用提供环境信息 | |
env = {} | |
env['wsgi.version'] = (1, 0) | |
env['wsgi.url_scheme'] = 'http' | |
env['wsgi.input'] = StringIO.StringIO(self.request_data) | |
env['wsgi.errors'] = sys.stderr | |
env['wsgi.multithread'] = False | |
env['wsgi.multiprocess'] = False | |
env['wsgi.run_once'] = False | |
# Required CGI variables | |
env['REQUEST_METHOD'] = self.request_method # GET | |
env['PATH_INFO'] = self.path # /hello | |
env['SERVER_NAME'] = self.server_name # localhost | |
env['SERVER_PORT'] = str(self.server_port) # 8888 | |
return env | |
def start_response(self, status, response_headers, exc_info=None): | |
server_headers = [('Date', 'Tue, 31 Mar 2015 12:54:48 GMT'), ('Server', 'WSGIServer 0.2')] | |
self.headers_set = [status, response_headers + server_headers] | |
def finish_response(self, result): | |
#关闭 socket 端口,将数据返回至客户端 | |
try: | |
status, response_headers = self.headers_set | |
response = 'HTTP/1.1 {status}\r\n'.format(status=status) | |
for header in response_headers: | |
response += '{0}: {1}\r\n'.format(*header) | |
response += '\r\n' | |
for data in result: | |
response += data | |
self.client_connection.sendall(response) | |
print(''.join( | |
'> {line}\n'.format(line=line) | |
for line in response.splitlines() | |
)) | |
finally: | |
self.client_connection.close() | |
SERVER_ADDRESS = (HOST, PORT) = '', 8888 | |
def make_server(server_address, application): | |
server = WSGIServer(server_address) | |
server.set_app(application) | |
return server | |
if __name__ == '__main__': | |
if len(sys.argv) < 2: | |
sys.exit('Provide a WSGI application object as module:callable') | |
app_path = sys.argv[1] | |
module, application = app_path.split(':') # 第一个参数是文件名,第二个参数时长文件内app的命名 | |
module = __import__(module) | |
application = getattr(module, application) | |
httpd = make_server(SERVER_ADDRESS, application) | |
print('WSGIServer: Serving HTTP on port {port} ...\n'.format(port=PORT)) | |
httpd.serve_forever() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment