python wsgi 规范 与java的servlet规范比较

1. wsgi 是python的特有规范, 与java的servlet规范一样, java特有

搞这个规范干嘛呢:


简单socket:

执行下面代码, 在浏览器里面执行:http://localhost:8001/, 我们可以看到hello


打印信息如下:

GET / HTTP/1.1
Host: localhost:8001
Connection: keep-alive
Cache-Control: max-age=0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0
.8
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like
Gecko) Chrome/40.0.2214.91 Safari/537.36
Accept-Encoding: gzip, deflate, sdch
Accept-Language: zh-CN,zh;q=0.8




recv from  ('127.0.0.1', 51045)
GET /favicon.ico HTTP/1.1
Host: localhost:8001
Connection: keep-alive
Accept: */*
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like
Gecko) Chrome/40.0.2214.91 Safari/537.36
Accept-Encoding: gzip, deflate, sdch
Accept-Language: zh-CN,zh;q=0.8


#coding=utf8

import socket

so = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
so.bind(('', 8001))
so.listen(1)
while True:
    conn, addr = so.accept()
    print "recv from ", addr
    msg = ''
    while True:
        buff = conn.recv(1024)
        if not buff: break
        if len(buff) < 1024: 
            msg += buff
            break

        msg += buff
        
    print msg
    conn.send("hello")
    conn.close()
    
    


python自带实现wsgi的源码wsgiref模块:

参考下点击打开链接

源码里面的一个例子:

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,'=', repr(v)
    start_response("200 OK", [('Content-Type','text/plain')])
    return [stdout.getvalue()]

httpd = make_server('localhost', 8002,  demo_app)
httpd.serve_forever()  # 使用select
make_server是不是很眼熟, 没错:

make_server(host, port, app, server_class=, handler_class=)

与我们之前写的scoket多了一个回调方法而已.

再看源码:

def make_server(
    host, port, app, server_class=WSGIServer, handler_class=WSGIRequestHandler
):
    """Create a new WSGI server listening on `host` and `port` for `app`"""
    server = server_class((host, port), handler_class)
    server.set_app(app)
    return server

class WSGIServer(HTTPServer):

    """BaseHTTPServer that implements the Python WSGI protocol"""


class TCPServer(BaseServer):

    """Base class for various socket-based server classes.

    Defaults to synchronous IP stream (i.e., TCP). """

    address_family = socket.AF_INET

    socket_type = socket.SOCK_STREAM

    request_queue_size = 5

    allow_reuse_address = False

    def __init__(self, server_address, RequestHandlerClass, bind_and_activate=True):
        """Constructor.  May be extended, do not override."""
        BaseServer.__init__(self, server_address, RequestHandlerClass)
        self.socket = socket.socket(self.address_family,
                                    self.socket_type)
        if bind_and_activate:
            self.server_bind()
            self.server_activate()

    def server_bind(self):
        """Called by constructor to bind the socket.

        May be overridden.

        """
        if self.allow_reuse_address:
            self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        self.socket.bind(self.server_address)
        self.server_address = self.socket.getsockname()



 
  
class BaseServer:

    """Base class for server classes.

    Methods for the caller:

    - __init__(server_address, RequestHandlerClass)
    - serve_forever(poll_interval=0.5)
    - shutdown()
    - handle_request()  # if you do not use serve_forever()
    - fileno() -> int   # for select()

    Methods that may be overridden:

    - server_bind()
    - server_activate()
    - get_request() -> request, client_address
    - handle_timeout()
    - verify_request(request, client_address)
    - server_close()
    - process_request(request, client_address)
    - close_request(request)
    - handle_error()

从上面源码可以看出TCPServer不就是socket.socket(socket.AF_INET, socket.SOCK_STREAM)


然后我从BaseHttpRequestHandler看到这个, 结合上面的打印, 我草,就是这么解析的啊

words = requestline.split()
if len(words) == 3:
    [command, path, version] = words
    if version[:5] != 'HTTP/':
        self.send_error(400, "Bad request version (%r)" % version)
        return False

然后我从BaseHandler找到了这个

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.
python的WSGI( Python Web Server Gateway Interface)规范定义基本清楚.

先说Java的servlet,  单实例多线程运行,如果需要wsgi也可以这样.

Java的servlet, 针对我们的应用, 我们需要实现doGet, doPost

Java的serlvet, 我们不使用中介件tomcat, jboss, resin也是可以的启动一个java的web服务的

WSGI规范了,web应用与web服务分离的结合.   浏览器----httpServer----AppServer


参考源码自己写了一个玩:

#coding=utf8

import socket
import select
import sys
import os
import threading
import time

class BaseServer():
    
    def __init__(self, server_addr, RequestHandlerClass):
        self.server_addr = server_addr
        self.RequestHandlerClass = RequestHandlerClass
        self.__shutdown_request = True

    def finish_request(self):
        # verify 
        self.request, client_addr = self.get_request()  #  accept 由于是可读, 故非阻塞
        self.RequestHandlerClass(self.request, client_addr, self)
        print "fileno:", self.request.fileno()
        self.request.close()
        time.sleep(3)
        # handle error
         
    def serve_forever(self, poll_interval=0.5):
        threading.Event().clear()
        try:
            while self.__shutdown_request:
                r, w, e = select.select([self], [], [], poll_interval)
                if self in r:
                    self.finish_request()
        finally:
            self.__shutdown_request = False

class TCPServer(BaseServer):

    def __init__(self, server_addr, RequestHandlerClass):
        BaseServer.__init__(self, server_addr, RequestHandlerClass)
        self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.server_bind()
     
    def server_bind(self):
        self.socket.bind(self.server_addr)  # host, port
        self.socket.listen(5)
        
    def get_request(self):
        return self.socket.accept()
    
    def fileno(self):
        """
        Return socket file number by select()
        """
        return self.socket.fileno()

class HttpServer(TCPServer):
    
    def server_bind(self):
        TCPServer.server_bind(self)

class WSGIServer(HttpServer):
    
    def server_bind(self):
        env = self.base_env = {}
        HttpServer.server_bind(self)

    def get_app(self):
        return self.app

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

# --------------------------------------------- #
class BaseHandler:
    wsgi_version = (1, 0)
    os_env = dict(os.environ.items())

    def setup_env(self):
        self.env = self.os_env.copy()
        # todo wsgi.env
    
    def _write(self, data):
        pass

    def start_response(self, status, headers, exc_info=None):
        self.status = status
        self.headers = headers

    def run(self, app):
        self.setup_env()
        self.result = app(self.env, self.start_response)
        print self.result
        for data in self.result:
            self._write(data)
            self._flush()

        self.close()

    def setup_env(self):
        self.env = self.os_env
        
    def close(self):
        pass

    def write(self, data):
        raise NotImplementedError

    def _flush():
        raise NotImplementedError

class SimpleHandler(BaseHandler):
    def __init__(self,stdin, stdout,stderr, env):
        self.stdin = stdin
        self.stdout = stdout
        self.stderr = stderr
        self.base_env = env

    def write(self,data):
        self._write(data)
        self._flush()

    def _write(self, data): 
        self.stdout.write(data)
        self._write = self.stdout.write
    
    def _flush(self):
        self.stdout.flush()
        self._flush = self.stdout.flush
       

class ServerHandler(SimpleHandler):
    pass

# --------------------------------------------- #
class BaseRequestHandler():

    def __init__(self, request, client_addr, server):
        self.request = request
        self.clinet_addr = client_addr
        self.server = server
        self.setup()
        self.handle()
        self.finish()

    def setup(self):
        pass

    def handle(self):
        pass
    
    def finish(self):
        pass

class StreamRequestHandler(BaseRequestHandler):
    
    def setup(self):
        self.conn = self.request
        self.rfile = self.conn.makefile('rb', -1)
        self.wfile = self.conn.makefile('wb', -1)

class BaseHTTPRequestHandler(StreamRequestHandler):
    pass

class WSGIRequestHandler(BaseHTTPRequestHandler):

    def get_env(self):
        env = self.server.base_env.copy()
        return env

    def handle(self):
        # todo 检验请求格式合法
        handler = ServerHandler(self.rfile, self.wfile, sys.stderr, self.get_env())
        handler.run(self.server.get_app())

# -------------------------------------- # 
def demo_app(environ, start_response):
    start_response("200 OK", [('Content-Type','text/plain')])
    import random
    r = random.randint(0,100)
    return ['hello, world: ' + str(r), 'fds']


def http_server(host, port, app, server_class=WSGIServer, handler_class=WSGIRequestHandler):
    server = server_class((host, port), handler_class)
    server.set_app(app)
    return server

def test():
    httpd = http_server('192.168.41.77', 8003, demo_app)
    httpd.serve_forever()

if __name__ == "__main__":
    test()


你可能感兴趣的:(python wsgi 规范 与java的servlet规范比较)