带你快速了解WSGI

研究python,肯定会碰到wsgi这个单词的时候,刚碰到的时候是不是灰常的困惑。没事,我也是,但我有耐心研究,查资料,现在我基本懂了,把看到的资料和自己的理解分享给大家,希望你也能懂?

step 1 简单了解ip/tcp http socket

这一步是必须的,要不然到后面wsgi的时候你会晕的。

我说了简单,所以具体的你可以到官网去深入了解

所以,你只需要知道

(1)ip 协议是规定网络层面的协议
(2)tcp 协议是基于ip协议,规定数据传输层面的协议
(3)http 协议是规定应用层面,建立在ip/tcp基础之上的一种应用,也称作超文本传送协议(Hypertext Transfer Protocol )。我们可以仅使用tcp/ip进行数据的传输,但我们也需要http协议来更好的展示我们的数据。http协议提供了显示数据的具体形式。
(4)socket 封装了ip/tcp协议,提供了一套调用接口。(你一定见到过socket.connect()这种函数,反正我见过),有了socket,你可以更方便的使用ip/tcp协议进行传输数据。

看到这里,你应该有了不小的收获,也有了一些基本的理解。接下来进入第二步。

step 2 通用网关接口 cgi

python 基础教程中的解释:cgi是网络服务器可以将查询传递到专门的程序中并且在网页上显示结果的标准机制。

下面这段话转载某博客,我觉得说的清楚明了。
最早的Web服务器简单地响应浏览器发来的HTTP请求,并将存储在服务器上的HTML文件返回给浏览器,也就是静态html。事物总是不 断发展,网站也越来越复杂,所以出现动态技术。但是服务器并不能直接运行 php,asp这样的文件,自己不能做,外包给别人吧,但是要与第三做个约定,我给你什么,然后你给我什么,就是握把请求参数发送给你,然后我接收你的处 理结果给客户端。那这个约定就是 common gateway interface,简称cgi。这个协议可以用vb,c,php,python 来实现。cgi只是接口协议,根本不是什么语言。下面图可以看到流程

http://images.cnitblog.com/blog/353089/201408/222132422994681.gif

服务器与浏览器之间采用的http传输协议

step 3 wsgi 和它的实现

WSGI(Python Web Server Gateway Interface)就是Python的CGI包装,为Python语言定义的Web服务器和Web应用程序或框架之间的一种简单而通用的接口。

用Python进行web开发时,你会接触到许多框架,这些框架封装了一些常用的功能方便应用程序的开发。

我们把用flask开发好的python应用程序applyprc部署到一个服务器上,比如说apache,然后我们的服务端就搭建好了。包括一个应用程序加一个服务器程序。

用过Apache的都知道,要启动它监听端口,并将程序与域名绑定。其实这就是一个根据http协议建立连接的过程。

现在我们的服务器程序等待监听客户段发来的请求,然后调用我们相应的应用程序applyprc,返回结果给客户端。

如果现在我们想换一个其他框架开发的applyprc部署到我们的apache上呢? 假如说这个框架没有遵循wsgi,那么我们的apache是不是还得适应你一下?好吧,那过两天我们又换了一个框架,仍没有遵循wsgi,那。。。或许你会成为一个牛逼的服务器开发人员。

如果我们所有web 框架开发人员都遵循wsgi来开发,是不是就没这么多事了,随便你选嘛框架。

WSGI规定:

1、开发的应用程序必须是一个可调用的对象,接受2个参数,然后返回一个可迭代的对象。(到这里可以去看看我之前的迭代器与生成器)
2、服务器程序必须负责配置好应用程序的两个参数,并调用应用程序,迭代访问应用程序返回的结果,然后传回客户端。

只要满足这两点,应用程序与服务器程序就可以配合使用了。

wsgiref是 Python标准库给出的 WSGI的参考实现,可以通过研究它的源码来更深入的了解wsgi。

我大概缕了一遍

#simple_server.py
#demo_app是应用程序,满足wsgi对应用程序的要求
def demo_app(environ,start_response):
    from StringIO import StringIO
    stdout = StringIO()
    print >>stdout, "Hello world!"
    print >>stdout
    h = environ.items(); h.sort()
    for k,v in h:
        print >>stdout, k,'=',`v`
    start_response("200 OK", [('Content-Type','text/plain')]) #返回body前 要先返回header所以此处调用一下
    return [stdout.getvalue()] #返回的可迭代对象list 返回body内容,通过self.finish_response返回客户端/浏览器

#服务器程序
#make_server函数调用WSGIServer(继承自HTTPServer类)完成了端口的绑定,建立连接,指定处理函数WSGIRequestHandler
def make_server(
    host, port, app, server_class=WSGIServer, handler_class=WSGIRequestHandler
):
    """Create a new WSGI server listening on `host` and `port` for `app`"""
  #为app在host和port上创建一个新的WSGI服务监听
    server = server_class((host, port), handler_class)
  #server与处理程序WSGIRequestHandler关联
    server.set_app(app)
    return server 


if __name__ == '__main__':
    httpd = make_server('', 8000, demo_app)
    sa = httpd.socket.getsockname() #获取正在通信的ip 与端口
    print "Serving HTTP on", sa[0], "port", sa[1], "..."
    import webbrowser
    webbrowser.open('http://localhost:8000/xyz?abc') #模拟浏览器访问
    httpd.handle_request()  # serve one request, then exit #响应一次请求然后关闭
#handle_request 经过一系列继承传递最终转化为handle.run(demo_app)



具体可参照下面这位大神画的图
(http://img.blog.csdn.net/20140127182536359?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvb25fMXk=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
图上的各种继承,如果你了解了step 1,我想对你理解这张图会有很大的帮助。

还记得对服务器程序的要求吗?

# run函数内部实现了对application的调用
    def run(self, application):
        """Invoke the application"""
        # Note to self: don't move the close()!  Asynchronous servers shouldn't
        # call close() from finish_response(), so if you close() anywhere but
        # the double-error branch here, you'll break asynchronous servers by
        # prematurely closing.  Async servers must return from 'run()' without
        # closing if there might still be output to iterate over.
        try:
            self.setup_environ() #配置好了参数
            self.result = application(self.environ, self.start_response) #调用
            self.finish_response()#返回访问结果给客户端 看这里!
        except:
            try:
                self.handle_error()
            except:
                # If we get an error handling an error, just give up already!
                self.close()
                raise   # ...and let the actual server figure it out.
#配置environ的函数
    def setup_environ(self):
        """Set up the environment for one request"""

        env = self.environ = self.os_environ.copy()
        self.add_cgi_vars()

        env['wsgi.input']        = self.get_stdin()
        env['wsgi.errors']       = self.get_stderr()
        env['wsgi.version']      = self.wsgi_version
        env['wsgi.run_once']     = self.wsgi_run_once
        env['wsgi.url_scheme']   = self.get_scheme()
        env['wsgi.multithread']  = self.wsgi_multithread
        env['wsgi.multiprocess'] = self.wsgi_multiprocess

        if self.wsgi_file_wrapper is not None:
            env['wsgi.file_wrapper'] = self.wsgi_file_wrapper

        if self.origin_server and self.server_software:
            env.setdefault('SERVER_SOFTWARE',self.server_software)
#检查并发送header的函数
    def start_response(self, status, headers,exc_info=None):
        """'start_response()' callable as specified by PEP 333"""

        if exc_info:
            try:
                if self.headers_sent:
                    # Re-raise original exception if headers sent
                    raise exc_info[0], exc_info[1], exc_info[2]
            finally:
                exc_info = None        # avoid dangling circular ref
        elif self.headers is not None:
            raise AssertionError("Headers already set!")

        assert type(status) is StringType,"Status must be a string"
        assert len(status)>=4,"Status must be at least 4 characters"
        assert int(status[:3]),"Status message must begin w/3-digit code"
        assert status[3]==" ", "Status message must have a space after code"
        if __debug__:
            for name,val in headers:
                assert type(name) is StringType,"Header names must be strings"
                assert type(val) is StringType,"Header values must be strings"
                assert not is_hop_by_hop(name),"Hop-by-hop headers not allowed"
        self.status = status
        self.headers = self.headers_class(headers)
        return self.write #返回head的组装对象。可调用。这里并不返回给客户端,等到在self.finish_response()中发射。

看到这里,我想你应该对wsgi有个大概的了解了吧!写了这么多,希望看到有收获的人能够点个赞,让我有动力继续写下去。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,189评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,577评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,857评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,703评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,705评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,620评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,995评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,656评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,898评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,639评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,720评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,395评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,982评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,953评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,195评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,907评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,472评论 2 342

推荐阅读更多精彩内容

  • 学过PHP的都了解,php的正式环境部署非常简单,改几个文件就OK,用FastCgi方式也是分分钟的事情。相比起...
    chen_000阅读 2,099评论 0 1
  • 转载自标点符的《网关协议学习:CGI、FastCGI、WSGI》 CGI CGI即通用网关接口(Common Ga...
    李绍俊阅读 1,655评论 0 1
  • 0 系列目录# WEB请求处理 WEB请求处理一:浏览器请求发起处理 WEB请求处理二:Nginx请求反向代理 本...
    七寸知架构阅读 13,876评论 22 190
  • 四个月的辛苦备战,四天五轮的竞争,省基本功大赛终于结束了。 结果很戏剧,我以零点零九分之差与一等奖失之交臂。但,我...
    朱朱82阅读 645评论 1 5
  • “快点到冬天啊。”这样就又可以躲进他的大衣里,把手伸进他的口袋里和他紧握,互相取暖。和他一起去吃热乎乎的麻辣...
    星星拌饭a阅读 253评论 0 3