Python入門教程: 一個基本的WSGI接口

主要參考: Let’s Build A Web Serve

服務(wù)器

#/usr/bin/env python
# -*- coding: utf-8 -*-

'''
    A module for WSGI: As a demostration
    Usage:
        python wsgiserver.py wsgiapp:app
'''

__author__ = 'Van Abel'

import socket
import StringIO
import sys


class WSGIServer(object):

    socket_family = socket.AF_INET
    socket_type = socket.SOCK_STREAM
    max_queue = 10

    def __init__(self, s_addr):
        # Create a listening socket
        self.s = s = socket.socket(
            self.socket_family,
                    self.socket_type
        )
        # Allow to reuse the same address
        s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        try:
            # Bind to addr, port
            s.bind(s_addr)
            # Listen on port
            s.listen(self.max_queue)
        except socket.error as e:
            print 'Server error >> %s ' % e
            sys.exit(1)
        # Get server host,port
        shost, self.s_port = self.s.getsockname()[:2]
        self.s_host = socket.getfqdn(shost)
        # Return headers set by web framework/app
        self.headers = []

    def set_app(self, app):
        self.app = app

    def server_forever(self):
        s = self.s
        while True:
            # New client conn
            self.c_conn, c_addr = s.accept()
            # Handle request and close
            #   Then loop over to wait for another client conn
            self.handle()

    def handle(self):
        # Read request from client
        self.r_data = r_data = self.c_conn.recv(1024)
        # Print formatted request data as 'curl -v'
        print(''.join(
            '< {line}\n'.format(line=line)
                for line in r_data.splitlines()
        ))
        # Parse the request
        self.parse(r_data)

        # Construct environment dict useing r_data
        env = self.get_env()

        # Call app(defined in wsgiapp.py and pass in by set_app())
        #   and get result as HTTP response body
        b_data = self.app(env, self.start)

        # Construct a response and send to client
        self.send(b_data)

    def parse(self, data):
        headers = data.splitlines()[0].rstrip('\r\n')
        # Break down the headers
        (
            self.method,
            self.path,
            self.protcl
        ) = headers.split()

    def get_env(self):
        env = {}

        # Required WSGI variables
        env['wsgi.version'] = (1, 0)
        env['wsgi.url_scheme'] = 'http'
        env['wsgi.input'] = StringIO.StringIO(self.r_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.method
        env['PATH_INFO'] = self.path
        env['SERVER_NAME'] = self.protcl
        env['SERVER_PORT'] = str(self.s_port)

        return env

    def start(self, status, r_headers, exc_info=None):
        # Add necessary server header
        s_headers = [
            ('Data', 'Tue, 19 Dec 2017 15:23:41 CST'),
                ('Server', 'WSGI Server 0.1')
        ]
        self.headers = [status, r_headers + s_headers]

    def send(self, body):
        try:
            status, r_headers = self.headers
            r = 'HTTP/1.x {status}\r\n'.format(status=status)
            for header in r_headers:
                r += '{0}: {1}\r\n'.format(*header)
            r += '\r\n'
            for data in body:
                r += data
            # Print formatted response data as 'curl -v'
            print(''.join(
                '> {line}\n'.format(line=line)
                for line in r.splitlines()
            ))
            self.c_conn.sendall(r)
        finally:
            self.c_conn.close()

SERVER_ADDRESS = (HOST, PORT) = '', 8000


def make_server(s_addr, app):
    server = WSGIServer(s_addr)
    server.set_app(app)
    return server

if __name__ == '__main__':
    if len(sys.argv) < 2:
        sys.exit('Usage:\n\tProvide a WSGI app object as module:callable')

    app_path = sys.argv[1]
    module, app = app_path.split(':')
    module = __import__(module)
    app = getattr(module, app)
    httpd = make_server(SERVER_ADDRESS, app)
    print('WSGIServer: Serving HTTP on port {port} ...\n'.format(port=PORT))
    httpd.server_forever()

客戶端

#/usr/bin/env python
# -*- coding: utf-8 -*-
'''
    wsgiapp.py
    A demo client for server_wsgi.py
'''
__author__ = 'Van Abel'

def app(environ, start):
    # A barebones WSGI app
    # you can take it as a start point of your webframework
    status = '200 OK'
    resp_h = [('Content-Type', 'text/plain')]
    start(status, resp_h)
    return 'Hello world from a simple WSGI app!\n'
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末蘸拔,一起剝皮案震驚了整個濱河市展氓,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌斋扰,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,539評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件券盅,死亡現(xiàn)場離奇詭異景描,居然都是意外死亡,警方通過查閱死者的電腦和手機偏化,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,594評論 3 396
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來镐侯,“玉大人侦讨,你說我怎么就攤上這事」斗” “怎么了韵卤?”我有些...
    開封第一講書人閱讀 165,871評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長崇猫。 經(jīng)常有香客問我沈条,道長,這世上最難降的妖魔是什么诅炉? 我笑而不...
    開封第一講書人閱讀 58,963評論 1 295
  • 正文 為了忘掉前任蜡歹,我火速辦了婚禮,結(jié)果婚禮上涕烧,老公的妹妹穿的比我還像新娘月而。我一直安慰自己,他們只是感情好议纯,可當我...
    茶點故事閱讀 67,984評論 6 393
  • 文/花漫 我一把揭開白布父款。 她就那樣靜靜地躺著,像睡著了一般瞻凤。 火紅的嫁衣襯著肌膚如雪憨攒。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,763評論 1 307
  • 那天阀参,我揣著相機與錄音浓恶,去河邊找鬼。 笑死结笨,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播炕吸,決...
    沈念sama閱讀 40,468評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼伐憾,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了赫模?” 一聲冷哼從身側(cè)響起树肃,我...
    開封第一講書人閱讀 39,357評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎瀑罗,沒想到半個月后胸嘴,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,850評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡斩祭,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,002評論 3 338
  • 正文 我和宋清朗相戀三年劣像,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片摧玫。...
    茶點故事閱讀 40,144評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡耳奕,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出诬像,到底是詐尸還是另有隱情屋群,我是刑警寧澤,帶...
    沈念sama閱讀 35,823評論 5 346
  • 正文 年R本政府宣布坏挠,位于F島的核電站芍躏,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏降狠。R本人自食惡果不足惜对竣,卻給世界環(huán)境...
    茶點故事閱讀 41,483評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望喊熟。 院中可真熱鬧柏肪,春花似錦、人聲如沸芥牌。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,026評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽壁拉。三九已至谬俄,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間弃理,已是汗流浹背溃论。 一陣腳步聲響...
    開封第一講書人閱讀 33,150評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留痘昌,地道東北人钥勋。 一個月前我還...
    沈念sama閱讀 48,415評論 3 373
  • 正文 我出身青樓炬转,卻偏偏與公主長得像,于是被迫代替她去往敵國和親算灸。 傳聞我的和親對象是個殘疾皇子扼劈,可洞房花燭夜當晚...
    茶點故事閱讀 45,092評論 2 355