自带的httpserver

gunicorn自带了一个python wsgi http server,是为了默认的syncworker而设计的。

class SyncWorker(base.Worker):

    def run(self):
        # self.socket appears to lose its blocking status after
        # we fork in the arbiter. Reset it here.
        self.socket.setblocking(0)

        while self.alive:
            self.notify()

            # Accept a connection. If we get an error telling us
            # that no connection is waiting we fall down to the
            # select which is where we'll wait for a bit for new
            # workers to come give us some love.
            try:
                client, addr = self.socket.accept()
                client.setblocking(1)
                util.close_on_exec(client)
                self.handle(client, addr)

                # Keep processing clients until no one is waiting. This
                # prevents the need to select() for every client that we
                # process.
                continue

            except socket.error, e:
                if e[0] not in (errno.EAGAIN, errno.ECONNABORTED):
                    raise

终于在这里看到了久违的self.socket.accept(),接收一个访问连接,由self.handle(client, addr)来处理客户端来的请求命令。

class SyncWorker(base.Worker):

    #......

    def handle(self, client, addr):
        try:
            parser = http.RequestParser(client)
            req = parser.next()
            self.handle_request(req, client, addr)
        except StopIteration, e:
            self.log.debug("Closing connection. %s", e)
        except socket.error, e:
            if e[0] != errno.EPIPE:
                self.log.exception("Error processing request.")
            else:
                self.log.debug("Ignoring EPIPE")
        except Exception, e:
            self.handle_error(client, e)
        finally:
            util.close(client)

从http.RequestParser(client)进入http模块中,在self.handle_request(req, client, addr)中调用wsgi模块

class SyncWorker(base.Worker):

    #......

    def handle_request(self, req, client, addr):
        environ = {}
        try:
            self.cfg.pre_request(self, req)
            request_start = datetime.now()
            resp, environ = wsgi.create(req, client, addr,
                    self.address, self.cfg)
            # Force the connection closed until someone shows
            # a buffering proxy that supports Keep-Alive to
            # the backend.
            resp.force_close()
            self.nr += 1
            if self.nr >= self.max_requests:
                self.log.info("Autorestarting worker after current request.")
                self.alive = False
            respiter = self.wsgi(environ, resp.start_response)
            try:
                if isinstance(respiter, environ['wsgi.file_wrapper']):
                    resp.write_file(respiter)
                else:
                    for item in respiter:
                        resp.write(item)
                resp.close()
                request_time = datetime.now() - request_start
                self.log.access(resp, environ, request_time)
            finally:
                if hasattr(respiter, "close"):
                    respiter.close()
        except socket.error:
            raise
        except Exception, e:
            # Only send back traceback in HTTP in debug mode.
            self.handle_error(client, e)
            return
        finally:
            try:
                self.cfg.post_request(self, req, environ)
            except:
                pass

其中涉及到wsgi模块的有:

resp, environ = wsgi.create(req, client, addr,
                    self.address, self.cfg)

获得最终的响应结果:

respiter = self.wsgi(environ, resp.start_response)

这里的self.wsgi的踪迹在哪里呢?

  1. 由base.Worker中的方法init_process()中调用
self.init_signals()

self.wsgi = self.app.wsgi()

# Enter main run loop
self.booted = True
self.run()
  1. 在app,也就是wsgiapp或djangoapp中WSGIApplication -> Application中,有
def wsgi(self):
    if self.callable is None:
        self.callable = self.load()
    return self.callable
  1. 直接由self.load()执行,回转到WSGIApplication中的load()
def load(self):
    return util.import_app(self.app_uri)
  1. 调用util模块中的import_app(self.app_uri)
def import_app(module):
    parts = module.split(":", 1)
    if len(parts) == 1:
        module, obj = module, "application"
    else:
        module, obj = parts[0], parts[1]

    try:
        __import__(module)
    except ImportError:
        if module.endswith(".py") and os.path.exists(module):
            raise ImportError("Failed to find application, did "
                "you mean '%s:%s'?" % (module.rsplit(".",1)[0], obj))
        else:
            raise

    mod = sys.modules[module]
    app = eval(obj, mod.__dict__)
    if app is None:
        raise ImportError("Failed to find application object: %r" % obj)
    if not callable(app):
        raise TypeError("Application object must be callable.")
    return app

这才是最终wsgi应用程序的发起。还记得我们在快速入门中编写的简单wsgi程序么?

那么我们就在这里加上一句print,看看是不是:

print u'waiting for you ...(%s, %s)' % (module, obj)

再执行命令:

$ gunicorn --workers=2 myapp:app

结果如下:

(mypy)hzg@xubuntu:~/sample$ gunicorn --workers=2 myapp:app
2012-02-16 08:45:09 [2007] [INFO] Starting gunicorn 0.13.4
2012-02-16 08:45:09 [2007] [INFO] Listening at: http://127.0.0.1:8000 (2007)
2012-02-16 08:45:09 [2007] [INFO] Using worker: sync
2012-02-16 08:45:09 [2010] [INFO] Booting worker with pid: 2010
waiting for you ...(myapp, app)
2012-02-16 08:45:09 [2011] [INFO] Booting worker with pid: 2011
waiting for you ...(myapp, app)