Skip to content

Instantly share code, notes, and snippets.

@polebug
Created November 7, 2017 13:10
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save polebug/054c32c3104390c83b49e2279f1a3131 to your computer and use it in GitHub Desktop.
Save polebug/054c32c3104390c83b49e2279f1a3131 to your computer and use it in GitHub Desktop.
WSGI server 基本实现
#!/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