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. mongo 改数据库名称

    用命令 db.copyDatabase('old_name', 'new_name') 可以备份出一个新的数据库. 然后  use old_name 并db.dropDatabase() 即可删除旧的 ...

  2. How to make mail more effectively?

    1.What does your reader need to know? 2.What does your reader know already? 3.Will your reader be ab ...

  3. python夜记

    关于多行字符串(multi-line strings)的表现: Python列表是基于0索引的.(zero-indexed). 晌午起床来嘞,再来些笔记: Treasures 1: 列表方法rever ...

  4. 机器学习基础梳理—(accuracy,precision,recall浅谈)

    一.TP TN FP FN TP:标签为正例,预测为正例(P),即预测正确(T) TN:标签为负例,预测为负例(N),即预测正确(T) FP:标签为负例,预测为正例(P),即预测错误(F) FN:标签 ...

  5. php对字符串的操作

    php最文字的处理很是强大,之前一直云里雾里,这次学习一下. 1,' 与 ”的区别 <?php //双引号中的特殊字符会被解析 echo "你好\t我好";echo &quo ...

  6. 如何创建redis集群

    1.下载redis源码包 wget http://download.redis.io/releases/redis-3.2.4.tar.gz 2.解压并安装 tar xvf redis-.tar.gz ...

  7. 关于Spring+mybatis使用@Transactional注解事物没有生效的问题

    控制台日志信息: was not registered for synchronization because synchronization is not active JDBC Connectio ...

  8. Eclipse使用段注释格式化代码后混乱情况解决

    今天在Eclipse写代码用到段注释代码块注释一个方法,习惯使用格式化代码,结果一看格式化后的代码就乱了.就像下面那样. 觉得太乱了,而且不好对比检查.如果取消注释中间的**还保存了的,好纠结.于是就 ...

  9. maven的安装与使用(运行单元测试和打包等)

    maven的下载与安装 maven是用于java的自动化构建工具. 1.下载: http://maven.apache.org/download.cgi 下载maven包,比如 apache-mave ...

  10. Redis安装及局域网访问配置CentOS

    1.安装gcc,用来编译reids 通过命令 sudo yum install gcc 2.安装redis $ wget http://download.redis.io/releases/redis ...