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解析利用方法 ...
随机推荐
- Oracle中行转列,列转行pivot的用法
测试数据准备 --建表 --drop table SalesList; create table SalesList( keHu ), --客户 shangPin ), --商品名称 salesNum ...
- Apache Kafka(二)- Kakfa 安装与启动
安装并启动Kafka 1.下载最新版Kafka(当前为kafka_2.12-2.3.0)并解压: > wget http://mirror.bit.edu.cn/apache/kafka/2.3 ...
- 小匠第一周期打卡笔记-Task01
一.线性回归 知识点记录 线性回归输出是一个连续值,因此适用于回归问题.如预测房屋价格.气温.销售额等连续值的问题.是单层神经网络. 线性判别模型 判别模型 性质:建模预测变量和观测变量之间的关系,亦 ...
- Python多线程join/setDaemon
import threading, time class Test(): def test1(self): print("--") time.sleep(3) print(&quo ...
- Linux上安装nodejs
https://github.com/nodejs/node-v0.x-archive/wiki/Installing-Node.js-via-package-manager#debian-and-u ...
- 一文懂SSM项目中的web.xml常用配置项
做web后端工程师,逃不过的web.xml,我们都知道配置这个文件是日常工作了,那么我们来把一些必须知道知识点梳理下. 我们把web项目启动的时候,首先加载的就是web.xml这个文件,只有这个文件所 ...
- MODULE BUILD FAILED: ERROR: COULDN’T FIND PRESET “ES2015” RELATIVE TO DIRECTORY
npm run dev 遇到报错: Module build failed: Error: Couldn't find preset "es2015" relative to di ...
- redis架构
hash槽16384个,0-16383 master1(slave101,slave102) master2 (slave201,slave202) master 3 (slave30 ...
- Wx-公众号-关闭内置浏览器页面,返回公众号橱窗
方法一: pushHistory(); function pushHistory() { var state = { title: "title", url: "#&qu ...
- 爬虫(十一):selenium爬虫
1. selenium基础 selenium部分可以去看我写的selenium基础部分,由于链接太多了这里就不发出来了. 代理ip: 有时候频繁爬取一些网页.服务器发现你是爬虫后会封掉你的ip地址.这 ...