werkeug的WSGI服务器解析
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()
做了以下事情:
- 在selector上注册监听及处理触发
selector.register(self, selectors.EVENT_READ)
ready = selector.select(poll_interval)
if ready:
self._handle_request_noblock()
- 如果监听被触发了,调用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主要两个任务:
- 创建服务,监听端口
- 处理连接,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服务器解析的更多相关文章
- 服务器解析慢,可以安装nscd解决
针对服务器解析慢,可以在服务器上安装nscd,就可以把解析缓存起来,不用每次都解析 安装nscd: yum -y install nscd chkconfig nscd on service nscd ...
- Tomcat服务器解析“GET /JavaWebDemo1/1.jsp HTTP/1.1”
(2)服务器收到http请求报文,返回http响应报文 Tomcat服务器解析“GET /JavaWebDemo1/1.jsp HTTP/1.1” Tomcat服务器解析“GET /JavaWebDe ...
- 1元搭建自己的云服务器&解析域名
最近在学做微信开发,没有自己的域名和服务器就不得不寄人篱下,索性自己就到云主机上搭建了个服务器,但是水平有限弄了一个下午~~有自己的域名和服务器的好处相信不用我多说了.比如日后可以有自己域名的个性博客 ...
- 阿里云 云解析使用方法/在阿里云ESC服务器解析域名并绑定服务器IP后上传文件通过域名访问步骤教程
第一步:登录阿里云官网,获取服务器ECS的指定公网IP地址. 1.输入阿里云官网账号进入首页,如下图: 2.点击进入"管理控制台",如下图: 3.点击"云服务器ECS&q ...
- DNS服务器解析域名的过程
最近在读许令波老师的<深入分析Java Web技术内幕>,算是对DNS服务器域名解析有个大体的理解,以下的内容来自个人对书中内容的整理 1.什么是域名解析? 当我们在浏览器的地址栏输入一个 ...
- 域名注册域名解析域名绑定 dns服务器解析 域名记录的添加 记录类型含义@ www 访问域名请求过程
创建一个web应用,简言之就是访问一个域名,可以到达一个地方,这个地方就是你存放供别人查看的文件的地方 就像一条绳,从这头拉一下,可以拉出来另一头的东西 主要有两个部分: 域名 虚拟主机(空间) 1. ...
- JavaMail SMTP服务器发送邮件程序示例 java通过dns服务器解析ip地址
/** * JavaMail SMTP服务器发送邮件程序示例 * 扮演SMTP服务器角色与邮件客户端软件最大的区别就是: * SMTP服务器需要解析不同接收人邮件地址主机名对应的SMTP服务器主机名 ...
- NGINX本地服务器解析域名
1.找到hosts文件 ,添加需要解析的域名 2.在cmd命令窗口中检测解析是否生效 3 找到本地服务器的域名配置文件:添加绑定的域名,更改访问的目录 4.添加pathinfo.隐藏index.php ...
- web服务器解析漏洞总结(转)
转:http://www.secpulse.com/archives/3750.html 解析漏洞总结 2015 /1/27 22:09 一.IIS 5.x/6.0解析漏洞 IIS 6.0解析利用方法 ...
随机推荐
- pycharm通过unittest框架批量执行Python脚本用例
1.如下图点击进入配置页 2.新增一个配置,“2”标签选择要执行的脚本的目录或者脚本文件,“3”标签选择要执行的脚本的目录
- Word2010如何从指定页设置页码
光标定位:将光标定位于需要开始编页码的页首位置. 插入分隔符的”下一页”:选择“页面布局—>分隔符—> 下一页”插入. 插入页码:选择“插入—>页码—> 页面底端”,选 ...
- hdu1695(莫比乌斯反演+容斥)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1695 题目是求 在区间[a,b]选一个数x,区间[c,d]选一个数y,求满足gcd(x,y) = k ...
- 静态方法使用synchronized修饰.
package seday10;/** * @author xingsir * 静态方法若使用synchronized修饰,这个方法一定具有同步效果.静态方法上使用的同步监视器对象为这个类的" ...
- GitHub网页版基本操作
创建存储库 登录GitHub进入主页,点击头像左边的加号,创建存储库 填写存储库名称.描述,根据需求设置其他选项.点击“Create repository”按钮 创建分支 打开之前创建好的存储库,点击 ...
- 协同ADMM求解考虑碳排放约束直流潮流问题的对偶问题(A Distributed Dual Consensus ADMM Based on Partition for DC-DOPF with Carbon Emission Trading)
协同ADMM求解考虑碳排放约束直流潮流问题的对偶问题 (A Distributed Dual Consensus ADMM Based on Partition for DC-DOPF with Ca ...
- 吴裕雄 python 机器学习——集成学习随机森林RandomForestRegressor回归模型
import numpy as np import matplotlib.pyplot as plt from sklearn import datasets,ensemble from sklear ...
- Bug搬运工-CSCvg37458:ISR4K goes into booting loop with "flash:" in boot statement
ISR4K升级的时候要注意了! 很可能会碰到如下的问题: ISR4K goes into booting loop with "flash:" in boot statement ...
- 多种方式实现平均分栏布局(有间距)div平分行宽
以下例子基于分四栏+栏间有间距的例子分析 效果图: html代码: <div class="buy-one-buy"> <h3>淘一淘</h3> ...
- 搭建 VUE + NODE.JS + ElementUI 学习过程中问题总结
1.exports 和 module.exports require 用来加载代码,而 exports 和 module.exports 则用来导出代码. module.exports 初始值为一个空 ...