服务器采购框架合同协议书范本,手写一个满足WSGI协议的Server
在做Web開發時,一個很重要的概念就是服務端和應用程序之間的溝通協議,比如java中的servlet,由于servlet的存在,使得用java開發的web程序既可以跑在tomcat上,也可以是jetty。反之亦然。而在python中,對應的協議也就是WSGI協議,本文的目標就是實現一個可以支持python主流框架的web服務器,也幫助自己加強對WSGI協議的理解。
實驗環境:
python3.5
一個簡單的服務器實現
這一節并不會直接給出一個遵循WSGI協議規范的服務器,只是單純從如何與客戶端通信的角度來考慮實現。我們都知道,HTTP協議是建立在TCP協議的基礎上,所以首先我們借助python標準庫中的socket來實現TCP通信。下面是我的實現代碼和解釋:
# wsgi_a.py
import socket
HOST, PORT = '', 8888
listen_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
listen_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
listen_socket.bind((HOST, PORT))
listen_socket.listen(1)
print('Serving HTTP on port %s ...', PORT)
# run or not
flag = True
while flag:
try:
client_connection, client_address = listen_socket.accept()
request = client_connection.recv(1024)
print(request)
http_response = """\
HTTP/1.1 200 OK
Hello, World!
"""
client_connection.sendall(http_response.encode())
client_connection.close()
except KeyboardInterrupt:
flag = False
print('exit')
這里需要說明的是關于socket的標準庫中的基本函數及常量:
socket.socket(socket.AF_INET, socket.SOCK_STREAM) 返回一個socket對象,其中第一個參數需指明IP地址類型(IPv4, IPv6, ...),第二個參數用來指明通信的協議,這里兩個參數的意思分別為(IPv4, TCP)。
socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)設置套接字重用。
socket.bind((HOST,PORT))綁定端口
socket.listen(1) 設置客戶端的連接個數
socket.accept() 阻塞監聽
打開終端。命令行中運行該腳本并在瀏覽器中輸入
http://127.0.0.1:8888
即可查看結果。
滿足WSGI協議的服務器
簡單版本的服務器僅僅只是實現了與客戶端之間的通信,同時將請求處理也放在了服務器里,并沒有將兩者分開。也沒有對現有的主流框架進行支持。因此為了實現一個通用的Web服務器,根據WSGI協議,我們需要添加兩個關鍵的部分。一個傳給應用端的上下文環境,并一個是需要給應用端調用的start_response函數。詳情可以參照我之前的翻譯PEP333。
#wsgi_b.py
import socket
import sys, io
from datetime import date
class WSGIServer(object):
"""docstring for WSGIServer"""
def __init__(self, host, port, application):
self.host = host
self.port = port
self.listen_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.listen_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
self.listen_socket.bind((self.host, self.port))
self.listen_socket.listen(1)
self.flag = True
self.application = application
print('Serving HTTP on port %s ...', self.port)
def get_environ(self, request_data):
env = {}
# CGI variables
path, server, *args = request_data
env['REQUEST_METHOD'], env['PATH_INFO'], _= path.split()
env['SERVER_NAME'], env['SERVER_PORT'] = self.host, str(self.port)
# WSGI variables
env['wsgi.version'] = (1, 0)
env['wsgi.url_scheme'] = 'http'
env['wsgi.input'] = io.StringIO(self.request_data.decode())
env['wsgi.errors'] = sys.stderr
env['wsgi.multithread'] = False
env['wsgi.multiprocess'] = False
env['wsgi.run_once'] = False
return env
def make_server(self):
while self.flag:
try:
self.client_connection, self.client_address = self.listen_socket.accept()
self.request_data = self.client_connection.recv(1024)
request_data = self.request_data.decode().splitlines()
env = self.get_environ(request_data)
result = self.application(env, self.start_response)
self.make_response(result)
except KeyboardInterrupt:
self.flag = False
print('exit')
def make_response(self, result):
try:
status, response_headers = self.headers_set
response = 'HTTP/1.0 {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.decode()
self.client_connection.sendall(response.encode())
finally:
self.client_connection.close()
def start_response(self, status, response_headers, exc_info=None):
# Add necessary server headers
server_headers = [
('Date', date.today().strftime('%Y-%m-%d')),
('Server', 'WSGIServer 0.2'),
]
self.headers_set = [status, response_headers + server_headers]
這個版本的服務器實現了一個簡單的WSGI規范,但并不是全部,不過已經可以實現與多個框架的通信。相關的解釋如下:
WSGI的初始化參數分別為主機ip,端口及需要調用的應用程序。
get_environ函數,從request_data中獲取相應的CGI變量及WSGI變量,并傳給應用程序。
make_server,阻塞監聽端口。并接收客戶端傳來的消息交由應用程序進行處理,最后再將響應的結果打包,轉成響應格式,交付給客戶端。
make_response。將應用程序處理結果及請求頭打包成響應,并關閉連接。
start_response,這個函數交給應用程序調用,其參數分別為狀態碼,響應頭以及錯誤消息處理。
常見框架測試
這里是我的測試代碼,通過我們自己寫的服務器,可以成功的跑起weppy,flask及一個簡單的滿足WSGI規范的application。
# test.py
from wsgi_b import WSGIServer
from flask import Flask
from weppy import App
weppy_application = App(__name__)
flask_application = Flask(__name__)
@weppy_application.route("/")
def hello():
return "Hello World! from weppy"
@flask_application.route("/")
def hello():
return "Hello World! from flask"
def application(environ, start_response):
"""Simplest possible application object"""
status = '200 OK'
response_headers = [('Content-type', 'text/plain')]
start_response(status, response_headers)
return [b'Hello world! from simple app \n']
if __name__ == '__main__':
server = WSGIServer('127.0.0.1',8888,weppy_application).make_server()
但是這個服務器仍然還有許多需要完善的地方。不過不妨礙其做為學習WSGI協議時的補充。
總結
以上是生活随笔為你收集整理的服务器采购框架合同协议书范本,手写一个满足WSGI协议的Server的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: java struct工作原理_Stru
- 下一篇: python elif可以单独使用_Ce