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解析利用方法 ...
随机推荐
- 2020年算法设计竞赛 DP
链接:https://ac.nowcoder.com/acm/contest/3002/I来源:牛客网https://ac.nowcoder.com/acm/contest/3002/I 题目描述 & ...
- 5.Mybatis--解决属性名和字段名不一致的问题(起别名+resultMap)
我们看一下数据库中的字段 新建一个项目(我们拷贝之前的)来测试实体类字段跟数据库不一致 看看看,实体类中的属性是不是跟数据库表中的名不一样了 好,我们查询一下: 出现问题了:空值 为什么为空? 因为 ...
- 题解【洛谷P2513/CJOJ1345】[HAOI2009]逆序对数列
P1345 - [HAOI2009]逆序对数列 Description 对于一个数列{ai},如果有i<j且ai>aj,那么我们称ai与aj为一对逆序对数.若对于任意一个由1~n自然数组成 ...
- php preg正则表达式的组成部分
定界符号 : 多种都可以,常用为// 原子 : 最小的一个匹配单位 (放在定界符中),在一个正则表达式中,至少要有一个原子 1,打印字符(a-z A-Z 0-9 ~!@#$%^&*()_+.. ...
- ES+VBA 实现批量添加网络图片
需求:通过自动读取相对应列的图片网址,自动添加到图片列,从而完成添加图片 案例:需要将备注列的图片网址添加到图片列的内容 关键代码 '引入API Private Declare Function UR ...
- Some series and integrals involving the Riemann zeta function binomial coefficients and the harmonic numbers
链接:http://pan.baidu.com/s/1eSNkz4Y
- 查询数据操作:distinct
1.作用:distinct 去除重复记录.重复记录,指的是字段值,都相同的记录,而不是部分字段值相同的记录 与之相对的是all,表示所有.在MySQL中默认就是all. 2.例子: select ch ...
- js jquery 页面初始化加载
一.js 页面加载初始化方法 // 1.在body里面写初始化方法. <body onload='init()'> </body> <script type=" ...
- blog主题——田野(1)
贮存一下,blog代码 QAQ 页首html <link rel='stylesheet' href='https://blog-static.cnblogs.com/files/elkyo/c ...
- Linux centos7 shell 介绍、 命令历史、命令补全和别名、通配符、输入输出重定向
一.shell介绍 shell脚本是日常Linux系统管理工作中必不可少的,不会shell,就不是一个合格管理员. shell是系统跟计算机硬件交互使用的中间介质,一个系统工具.实际上在shell和计 ...