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解析利用方法 ...
随机推荐
- 路飞-git操作
复习 """ 1.pip换源 - 采用国内源下载,速度快 2.虚拟环境 - 可以为项目单独配置开发环境,方便管理依赖模块及模块的版本迭代 3.后台项目重构目录结构 4.后 ...
- js设计模式之实现观察者模式实例代码
前端界面 html代码 <body> <select name="" id="select"> <option value=&qu ...
- Flink流处理(二)- 流处理基本概念
1. Dataflow Programming 在讨论流处理的基本概念之前,我们首先介绍一下数据流编程(dataflow programming)的基本概念与术语. 数据流图 数据流程序一般在由数据流 ...
- 题解【SP2713】GSS4 - Can you answer these queries IV
题目描述 You are given a sequence \(A\) of \(N(N \leq 100,000)\) positive integers. There sum will be le ...
- 题解【POJ3252】Round Numbers
Description The cows, as you know, have no fingers or thumbs and thus are unable to play Scissors, P ...
- 【C语言】输入一个字符串,并对字符串中的偶数位置的字符按从小到大的顺序排序,奇数位置的字符不动,输出排序后的结果
#include <stdio.h> #include<string.h> int main() { ]; int i,j,k,len; gets_s(a); len= str ...
- Unity Coroutine详解(二)
• 介绍• Part 1. 同步等待• Part 2. 异步协程• Part 3. 同步协程• Part 4. 并行协程 1.介绍 ...
- Winform遍历窗口的所有控件(几种方式实现)
本文链接:https://blog.csdn.net/u014453443/article/details/85088733 扣扣技术交流群:460189483 C#遍历窗体所有控件或某类型所有控件 ...
- 密码学笔记——Rot13
Rot13:将每个在字母表上的字母,用后数13个后的字母代替,若超过时则重新绕回26字母开头即可. eg:A换成N.B换成O.依此类推到M换成Z,然后序列反转:N换成A.O换成B.最后Z换成M 1.密 ...
- pods " xxxx" not found错误
pods " xxxx" not found错误 待办 https://linuxacademy.com/community/show/29447-pod-is-not-found ...