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. 关于Javaweb的比较好用的jar包概述

    (连接数据库之前首先要导入这个数据库的驱动jar包 例如mysql 为mysql-connector-java-5.1.46.jar) 关于连接数据库的数据库连接池c3p0  jar包: c3p0-0 ...

  2. AcWing 874. 筛法求欧拉函数

    #include<bits/stdc++.h> using namespace std; typedef long long ll; ; int primes[N],cnt; int ph ...

  3. Linux - Shell - find - 进阶: 时间与大小

    概述 继续 find 这次的内容, 参数稍微要 复杂那么一丢丢 背景 刚学会了 基础 的参数 现在来了解一些 时间 和 空间 的参数 一说到操控时间空间, 感觉立马起来了... 准备 OS cento ...

  4. selenium定位方法-iframe元素定位方法

    在自动化测试中,如果无法定位到一个元素,那么最大的可能是定位的元素是在iframe框架中,iframe对象代表一个HTML的内联框架,在HTML中,iframe每出现一次,一个iframe对象就会被创 ...

  5. fader

    fader在音频处理中是比较基础的处理.通常用于平滑的调节音量,或是音频的渐入和渐出效果. 比较常见的fader有line和cubic线型的fader. line fader即fader的渐变过程是线 ...

  6. Python记:索引操作示例:将以数指定年,月,日的日期打印出来

    ————————————————————————————————————不要停止奔跑,不要回顾来路,来路无可眷恋,值得期待的只有前方. months=[ 'January', 'February', ...

  7. Pandas数据结构(一)——Pandas Series

    Pandas 是 Python 中基于Numpy构建的数据操纵和分析软件包,包含使数据分析工作变得快速简洁的高级数据结构和操作工具.通过Pandas Series 和 Pandas DataFrame ...

  8. 搭建FEBS权限系统

    在码云看到一个FEBS权限系统,但是没有找到搭建手册,自己记录一下. 1.下载项目:https://github.com/wuyouzhuguli/FEBS-Shiro2.创建数据库:执行sql文件夹 ...

  9. 百炼OJ - 1002 - 方便记忆的电话号码

    题目链接 思路 开个一千万的数组计数,最后遍历即可. #include<stdio.h> #include<string.h> #include<algorithm> ...

  10. 30分钟编写一个抓取 Unsplash 图片的 Python爬虫

       我一直想用 Python and Selenium 创建一个网页爬虫,但从来没有实现它. 几天前, 我决定尝试一下,这听起来可能是挺复杂的, 然而编写代码从 Unsplash 抓取一些美丽的图片 ...