werkeug的WSGI服务器解析

1.      WSGI

1.1.    wsgi与flask

flask默认的wsgi引用自wekurg

声明app:FLASK对象

app.run()

run_simple(host, port, self, **options)

引用自werkzurg.serving

host 主机

port 监听端口

self app本身

run_simple(host, port, self, **options)

host 主机

port 监听端口

self app本身

run_simple引用inner()

做了两件事,声明srv,运行它

srv = make_server(hostname, port, application, threaded,

processes, request_handler,

passthrough_errors, ssl_context,

fd=fd)

if fd is None:

srv.serve_forever()

看一下make_server()

它最终执行return BaseWSGIServer(host, port, app, request_handler,

passthrough_errors, ssl_context, fd=fd)

那么

srv = BaseWSGIServer()

class BaseWSGIServer(HTTPServer, object):

"""Simple single-threaded, single-process WSGI server."""

1.2.    WSGI server

是默认的server是BaseWSGIServer()

1.2.1.   初始化

初始化中执行了

HTTPServer.__init__(self, get_sockaddr(host, int(port),self.address_family), handler)

在这一过程中

创建socket,绑定,listen

核心属性释义:

self.socket

host,

port

self.server_address = server_address = get_sockaddr(host, int(port),self.address_family)

self.RequestHandlerClass = WSGIRequestHandler

至此,server对象创建完成并对端口进行监听。

中间还有一些上下文,ssl等处理,略过。

下面的一般就是构建一个死循环,处理请求,等待。。。

1.2.2.   serve_forever

上面BaseWSGIServer()已初始化完成,返回flask调用serve_forever

它实质是调用httpserver.serve_forever(self)

先看下BaseWSGIServer()

BaseWSGIServer():

def serve_forever(self):

self.shutdown_signal = False

try:

HTTPServer.serve_forever(self)

except KeyboardInterrupt:

pass

finally:

self.server_close()

继续向下,HTTPServer:

import socketserver

from http.server import HTTPServer, BaseHTTPRequestHandler

它基本继承于socketserver.TCPServer

class HTTPServer(socketserver.TCPServer):

socketserver.TCPServer基本继承于BaseServer

class TCPServer(BaseServer):

找到serve_forever

def serve_forever(self, poll_interval=0.5):

"""Handle one request at a time until shutdown.

Polls for shutdown every poll_interval seconds. Ignores

self.timeout. If you need to do periodic tasks, do them in

another thread.

"""

self.__is_shut_down.clear()

try:

# XXX: Consider using another file descriptor or connecting to the

# socket to wake this up instead of polling. Polling reduces our

# responsiveness to a shutdown request and wastes cpu at all other

# times.

with _ServerSelector() as selector:

selector.register(self, selectors.EVENT_READ)

while not self.__shutdown_request:

ready = selector.select(poll_interval)

if ready:

self._handle_request_noblock()

self.service_actions()

finally:

self.__shutdown_request = False

self.__is_shut_down.set()

做了以下事情:

  1. 在selector上注册监听及处理触发

selector.register(self, selectors.EVENT_READ)

ready = selector.select(poll_interval)

if ready:

self._handle_request_noblock()

  1. 如果监听被触发了,调用self._handle_request_noblock()

至此,服务算是跑起来了。

1.3.    请求处理

从socket开始,上面讲过触发监听后调用BaseWSGIServer() 的self._handle_request_noblock()

def _handle_request_noblock(self):

"""Handle one request, without blocking.

I assume that selector.select() has returned that the socket is

readable before this function was called, so there should be no risk of

blocking in get_request().

"""

try:

request, client_address = self.get_request()

# get_request实质是con, addr = self.socket.accept()

except OSError:

return

if self.verify_request(request, client_address):

try:

self.process_request(request, client_address)

except Exception:

self.handle_error(request, client_address)

self.shutdown_request(request)

except:

self.shutdown_request(request)

raise

else:

self.shutdown_request(request)

核心句是self.process_request(request, client_address)

最终是调用self.RequestHandlerClass(request, client_address, self)

上面讲过self.RequestHandlerClass = WSGIRequestHandler

到这里是监听到了一个客户端发起了连接,下面进入到连接及请示处理。

1.4.    WSGIRequestHandler

先看下定义及初始化

class WSGIRequestHandler(BaseHTTPRequestHandler, object):

"""A request handler that implements WSGI dispatching."""

class BaseHTTPRequestHandler(socketserver.StreamRequestHandler):

class StreamRequestHandler(BaseRequestHandler):

class BaseRequestHandler:

"""Base class for request handler classes.

def __init__(self, request, client_address, server):

self.request = request

self.client_address = client_address

self.server = server

self.setup()

try:

self.handle()

finally:

self.finish()

链条很长,在初始化时执行self.handle()

def handle(self):

"""Handles a request ignoring dropped connections."""

rv = None

try:

rv = BaseHTTPRequestHandler.handle(self)

except (socket.error, socket.timeout) as e:

self.connection_dropped(e)

except Exception:

if self.server.ssl_context is None or not is_ssl_error():

raise

if self.server.shutdown_signal:

self.initiate_shutdown()

return rv

def handle_one_request(self):

"""Handle a single HTTP request."""

self.raw_requestline = self.rfile.readline()

if not self.raw_requestline:

self.close_connection = 1

elif self.parse_request():

return self.run_wsgi()

后面代码比较长,简单点说

self.handle_one_request()的任务:

处理本次连接,收取报文,把socket recv的数据第一行(请求头)放到self.raw_requestline

然后调用self.parse_request(),负责把报文解析成http报文,提取出请求方法(get/post)

然后执行self.run_wsgi(),在其中执行下列语句:

self.environ = environ = self.make_environ()

# 生成上下文

最后execute(self.server.app)

# 交由app处理

execute定义:

def execute(app):

application_iter = app(environ, start_response)

try:

for data in application_iter:

write(data)

if not headers_sent:

write(b'')

finally:

if hasattr(application_iter, 'close'):

application_iter.close()

application_iter = None

释义:application_iter = app(environ, start_response)等于

Flask().__call__(environ, start_response)

然后flask返回数据,wsgi写入socket。

1.5.    flask

flask返回数据

核心是上下文,路由,执行view函数

最后由下面一句调用view function

return self.view_functions[rule.endpoint](**req.view_args)

2.      总结

WSGI主要两个任务:

  1. 创建服务,监听端口
  2. 处理连接,ip报文处理成http报文,转给app获取response,把response写入连接

据此有两大类class

第一类:服务

class BaseWSGIServer(HTTPServer, object):

class HTTPServer(socketserver.TCPServer):

它基本继承于socketserver.TCPServer

class TCPServer(BaseServer):

socketserver.TCPServer基本继承于BaseServer

分别是顶层应用,HTTP,TCP,socket四个层面的功能类。

第二类:请求处理

WSGIRequestHandler

class WSGIRequestHandler(BaseHTTPRequestHandler, object):

"""A request handler that implements WSGI dispatching."""

class BaseHTTPRequestHandler(socketserver.StreamRequestHandler):

类似的,分三层,WSGI,HTTP,SOCKET。

werkeug的WSGI服务器解析的更多相关文章

  1. 服务器解析慢,可以安装nscd解决

    针对服务器解析慢,可以在服务器上安装nscd,就可以把解析缓存起来,不用每次都解析 安装nscd: yum -y install nscd chkconfig nscd on service nscd ...

  2. Tomcat服务器解析“GET /JavaWebDemo1/1.jsp HTTP/1.1”

    (2)服务器收到http请求报文,返回http响应报文 Tomcat服务器解析“GET /JavaWebDemo1/1.jsp HTTP/1.1” Tomcat服务器解析“GET /JavaWebDe ...

  3. 1元搭建自己的云服务器&解析域名

    最近在学做微信开发,没有自己的域名和服务器就不得不寄人篱下,索性自己就到云主机上搭建了个服务器,但是水平有限弄了一个下午~~有自己的域名和服务器的好处相信不用我多说了.比如日后可以有自己域名的个性博客 ...

  4. 阿里云 云解析使用方法/在阿里云ESC服务器解析域名并绑定服务器IP后上传文件通过域名访问步骤教程

    第一步:登录阿里云官网,获取服务器ECS的指定公网IP地址. 1.输入阿里云官网账号进入首页,如下图: 2.点击进入"管理控制台",如下图: 3.点击"云服务器ECS&q ...

  5. DNS服务器解析域名的过程

    最近在读许令波老师的<深入分析Java Web技术内幕>,算是对DNS服务器域名解析有个大体的理解,以下的内容来自个人对书中内容的整理 1.什么是域名解析? 当我们在浏览器的地址栏输入一个 ...

  6. 域名注册域名解析域名绑定 dns服务器解析 域名记录的添加 记录类型含义@ www 访问域名请求过程

    创建一个web应用,简言之就是访问一个域名,可以到达一个地方,这个地方就是你存放供别人查看的文件的地方 就像一条绳,从这头拉一下,可以拉出来另一头的东西 主要有两个部分: 域名 虚拟主机(空间) 1. ...

  7. JavaMail SMTP服务器发送邮件程序示例 java通过dns服务器解析ip地址

    /** * JavaMail SMTP服务器发送邮件程序示例 * 扮演SMTP服务器角色与邮件客户端软件最大的区别就是: * SMTP服务器需要解析不同接收人邮件地址主机名对应的SMTP服务器主机名 ...

  8. NGINX本地服务器解析域名

    1.找到hosts文件 ,添加需要解析的域名 2.在cmd命令窗口中检测解析是否生效 3 找到本地服务器的域名配置文件:添加绑定的域名,更改访问的目录 4.添加pathinfo.隐藏index.php ...

  9. web服务器解析漏洞总结(转)

    转:http://www.secpulse.com/archives/3750.html 解析漏洞总结 2015 /1/27 22:09 一.IIS 5.x/6.0解析漏洞 IIS 6.0解析利用方法 ...

随机推荐

  1. es 6.x scroll用法

    我们可以使用from +size来获取所有数据,但是,如果数据量大的时候,这样的操作开销很大,这时候可以使用scroll操作 1.第一步发起一个scroll 的post请求,带上参数scroll=1m ...

  2. 题解【洛谷P5483】[JLOI2011]小A的烦恼

    我们可以灵活运用\(C++\)的语法来解决此题. 解释一下代码中会出现的语法: \(string::iterator\ it\)表示定义了一个\(string\)类型的迭代器\(it\),\(^*it ...

  3. 查看Oracle的SID的方式

    1  使用组合键“Win + R”打开运行对话框,在输入框中输入 regedit 并回车打开“注册表编辑器”. 2   在“注册表编辑器”对话框,依次展开 HKEY_LOCAL_MACHINE\SOF ...

  4. MinGW dll导入导出类

    dll不仅可以导入导出函数,还可以导入导出类.这篇文章就来介绍如何将类导入dll中并导出. 首先我们建立一个名为dll.cpp的文件(又是这种破名字),里面写上: #include <iostr ...

  5. 【转载】C++面试题(51-100)

    转自:http://www.jobui.com/mianshiti/it/cpp/5018/ 51.  引用与指针有什么区别? 答 .1) 引用必须被初始化,指针不必. 2) 引用初始化以后不能被改变 ...

  6. ThinkPHP中的时间自动填充 无法获取时间

    protected $_auto = array(       array('addTime','time','1','function'),    ); addTime在数据库里的的类型必须为int ...

  7. 转:为什么说Java中只有值传递

    原文:https://www.cnblogs.com/wchxj/p/8729503.html 错误理解 在开始深入讲解之前,有必要纠正一下大家以前的那些错误看法了.如果你有以下想法,那么你有必要好好 ...

  8. 树链剖分 (ZQU1607)

    这道题与模板之间,多了个确定哪个为根的操作: 这道题有技巧,并不需要真正去建立以某个节点为根的树 关于路径的操作,无论以哪个点为根,得出的答案无影响: 关于对子节点进行操作的,有几种情况, 当查询节点 ...

  9. 概率dp poj2096

    /** dp求期望的题. 题意:一个软件有s个子系统,会产生n种bug. 某人一天发现一个bug,这个bug属于某种bug,发生在某个子系统中. 求找到所有的n种bug,且每个子系统都找到bug,这样 ...

  10. lees入门

    安装 1 下载EasyLess插件 2 新建less文件,输入less语句,保存,就会在同级目录下生成同名的css文件 3 在HTML页面导入 <link rel="styleshee ...