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. 路飞-git操作

    复习 """ 1.pip换源 - 采用国内源下载,速度快 2.虚拟环境 - 可以为项目单独配置开发环境,方便管理依赖模块及模块的版本迭代 3.后台项目重构目录结构 4.后 ...

  2. js设计模式之实现观察者模式实例代码

    前端界面 html代码 <body> <select name="" id="select"> <option value=&qu ...

  3. Flink流处理(二)- 流处理基本概念

    1. Dataflow Programming 在讨论流处理的基本概念之前,我们首先介绍一下数据流编程(dataflow programming)的基本概念与术语. 数据流图 数据流程序一般在由数据流 ...

  4. 题解【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 ...

  5. 题解【POJ3252】Round Numbers

    Description The cows, as you know, have no fingers or thumbs and thus are unable to play Scissors, P ...

  6. 【C语言】输入一个字符串,并对字符串中的偶数位置的字符按从小到大的顺序排序,奇数位置的字符不动,输出排序后的结果

    #include <stdio.h> #include<string.h> int main() { ]; int i,j,k,len; gets_s(a); len= str ...

  7. Unity Coroutine详解(二)

    •        介绍•        Part 1. 同步等待•        Part 2. 异步协程•        Part 3. 同步协程•        Part 4. 并行协程 1.介绍 ...

  8. Winform遍历窗口的所有控件(几种方式实现)

    本文链接:https://blog.csdn.net/u014453443/article/details/85088733 扣扣技术交流群:460189483 C#遍历窗体所有控件或某类型所有控件 ...

  9. 密码学笔记——Rot13

    Rot13:将每个在字母表上的字母,用后数13个后的字母代替,若超过时则重新绕回26字母开头即可. eg:A换成N.B换成O.依此类推到M换成Z,然后序列反转:N换成A.O换成B.最后Z换成M 1.密 ...

  10. pods " xxxx" not found错误

    pods " xxxx" not found错误 待办 https://linuxacademy.com/community/show/29447-pod-is-not-found ...