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()
参考下点击打开链接
源码里面的一个例子:
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=
与我们之前写的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()