Flask(4)- flask请求上下文源码解读、http聊天室单聊/群聊(基于gevent-websocket)
一、flask请求上下文源码解读
通过上篇源码分析,我们知道了有请求发来的时候就执行了app(Flask的实例化对象)的__call__方法,而__call__方法返回了app的wsgi_app(environ, start_response)方法的执行结果,而wsgi_app方法中有这样一句话:ctx = self.request_context(environ),还分析除了ctx是RequestContext类的实例化对象,而且ctx中含有有本次请求的request对象和session对象。
接下来我们重点分析flask是如何做到把request对象当成全局变量,而又保证了数据安全,即请求信息互不影响的。
1、flask请求上文源码解读
上篇我们分析到了如何得到RequestContext实例化对象ctx,接下来ctx对象执行push方法,如下:
RequestContext类中的push方法源码如下:
_request_ctx_stack是LocalStack类的实例化对象:
LocalStack类中的__init__方法如下:
Local类的__init__方法如下:
get_ident是Local类所在文件中导入的一个方法名,该方法执行后会得到线程或协程ID,如下:
LocalStack类中的top是一个属性方法,源码如下:
下一步Local类中的__getattr__方法源码如下:
到此,分析得出top = _request_ctx_stack.top中的top为None。
接下来分析 _request_ctx_stack.push(self)做了什么?LocalStack类中的push方法源码如下:
Local类中的__setattr__方法源码如下:
因为rv.append(obj),所以最后LocalStack对象,即_request_ctx_stack对象字典化后如下:
- {'_local':{'__storage__':{9527:{stack:[ctx]}}, '__ident_func__':get_ident}}
- # 说明:9527假设是获取到的线程或者协程号,ctx包含request对象和session对象。
到此,flask请求上文结束,也就是完成了将一个request和session对象存储到某个地方。
2、下文
我们知道flask的request对象和session对象是全局变量,上文已经解读了如何存储。接下来解读如何在保证数据安全的情况下取出来,即只取到自己的请求信息而非其他人的。
我们还知道request对象中存储了很多信息,如request.method存储请求方式、request.json存储json标准字符串等等。下面以request.method为例,分析如何得到请求方式信息。
导入request方式如下:
- from flask import request
源码如下:
LocalProxy类的__init__方法如下:
偏函数中的原函数_lookup_req_object源码如下:
当执行request.method的时候,执行LocalProxy的__getattr__方法,源码如下:
查看类LocalProxy中的_get_current_object方法是如何得到本次请求的request对象,源码如下:
至此,我们已经分析出了如何得到本次请求的request对象,从而取出request对象中的相关信息。
二、http聊天室(单聊/群聊)- 基于gevent-websocket
1、准备知识
http协议特点:短连接,无状态保存;
轮询:前后端一秒交互多次,压力极大,并且消耗带宽,资源浪费极其严重;
长轮询:即让服务器保存我的一个连接状态,用于快速传递消息,节省带宽,释放压力,数据实时性强;
长连接:服务端及客户端节省极大的资源,能保证数据实时性;
带宽:1Mbps = 128KB/s
2、http聊天室
准备工作:下载gevent-websocket模块
- pip3 install gevent-websocket
代码示例:
manage.py代码:
- from flask import Flask, request, render_template
- from geventwebsocket.handler import WebSocketHandler
- from geventwebsocket.websocket import WebSocket # 提示用
- from gevent.pywsgi import WSGIServer
- import json
- app = Flask(__name__)
- user_socket_dict = {} # 用户字典
- @app.route('/ws/<username>')
- def ws(username):
- print(request.environ) # 有个wsgi.websocket,通过它可以发消息
- user_socket = request.environ.get('wsgi.websocket') #type:WebSocket
- if user_socket:
- user_socket_dict[username] = user_socket
- print(user_socket_dict)
- while 1:
- msg = user_socket.receive()
- msg_dict = json.loads(msg)
- msg_dict['from_user'] = username
- to_user = msg_dict.get('to_user')
- # chat = msg_dict.get('msg')
- u_socket = user_socket_dict.get(to_user) #type:WebSocket
- u_socket.send(json.dumps(msg_dict))
- @app.route('/')
- def index():
- return render_template('ws.html')
- if __name__ == '__main__':
- http_serv = WSGIServer(('0.0.0.0',9527), app, handler_class=WebSocketHandler)
- http_serv.server_forever()
ws.html代码:
- <!DOCTYPE html>
- <html lang="en">
- <head>
- <meta charset="UTF-8">
- <title>Title</title>
- </head>
- <body>
- <input id="username"type="text"><button onclick="login()">登录聊天室</button>
- 给<input id="to_user"type="text">
- <input id="msg"type="text"><button onclick="send_msg()">发送</button>
- <div id="chat_list"style="width:500px; height:500px; border:1px solid red;"></div>
- </body>
- <script type="text/javascript">
- var ws = null; // 因其他函数也可能会用到ws,所以不能放在某一个函数中
- function login() {
- var username = document.getElementById('username').value;
- var ws = new WebSocket('ws://192.168.13.172:9527/ws'+username); // ws请求协议
- ws.onmessage = function (data) {
- console.log(data.data);
- var recv_msg = JSON.parse(data.data);
- var ptag = document.createElement('p');
- ptag.innerText = recv_msg.from_user + ':' + recv_msg.msg;
- document.getElementById('caht_list').appendChild(ptag)
- };
- }
- function send_msg() {
- var to_user = document.getElementById('to_user').value;
- var msg = document.getElementById('msg').value;
- var send_dict = {
- 'to_user':to_user,
- 'msg':msg
- };
- ws.send(JSON.stringify(send_dict));
- }
- </script>
- </html>
Flask(4)- flask请求上下文源码解读、http聊天室单聊/群聊(基于gevent-websocket)的更多相关文章
- flask的请求上下文源码解读
一.flask请求上下文源码解读 通过上篇源码分析( ---Flask中的CBV和上下文管理--- ),我们知道了有请求发来的时候就执行了app(Flask的实例化对象)的__call__方法,而__ ...
- Flask系列10-- Flask请求上下文源码分析
总览 一.基础准备. 1. local类 对于一个类,实例化得到它的对象后,如果开启多个线程对它的属性进行操作,会发现数据时不安全的 import time from threading import ...
- flask 请求上下文源码(转)
本篇阅读目录 一.flask请求上下文源码解读 二.http聊天室(单聊/群聊)- 基于gevent-websocket 回到顶部 转:https://www.cnblogs.com/li-li/p/ ...
- Flask框架 (四)—— 请求上下文源码分析、g对象、第三方插件(flask_session、flask_script、wtforms)、信号
Flask框架 (四)—— 请求上下文源码分析.g对象.第三方插件(flask_session.flask_script.wtforms).信号 目录 请求上下文源码分析.g对象.第三方插件(flas ...
- Flask请求上下文源码讲解,简单的群聊单聊web
请求上下文流程图 群聊html代码 <!DOCTYPE html> <html lang="en"> <head> <meta chars ...
- flask请求上下文源码分析
一.什么是上下文 每一段程序都有很多外部变量,只有像add这种简单的函数才是没有外部变量的,一旦你的一段程序有了外部变量,这段程序就不完整了,不能独立运行,你为了使他们能运行,就要给所有的外部变量一个 ...
- Lumen开发:lumen源码解读之初始化(3)——单例(singleton)与中间件(Middleware)
版权声明:本文为博主原创文章,未经博主允许不得转载. 今天来讲讲Lumen的singleton和Middleware,先来看看起始文件bootstrap/app.php / * | --------- ...
- Flask请求和应用上下文源码分析
flask的request和session设置方式比较新颖,如果没有这种方式,那么就只能通过参数的传递. flask是如何做的呢? 1:本地线程,保证即使是多个线程,自己的值也是互相隔离 1 im ...
- Flask源码解读--所有可扩展点
一.前言 flask中有很多可扩展点(笔者这样称呼),其中包含了信号和请求钩子,这些信号和钩子有什么用呢?其主要作用用于帮助我们进行程序的耦合性,当然还可以让我们自定义一些行为.话不多说,通过阅读源码 ...
随机推荐
- List 通过 Collections.binarySearch 进行记录筛选
1. Collections.sort(list, new Comparator<TreeDto>() { @Override public int compare(TreeDto a2, ...
- ASP.NET Web API 使用Swagger生成在线帮助测试文档,支持多个GET
以下为教程: 在现有webapi项目中,nuget安装以下两个插件 swagger.net.ui swashbuckle 安装完毕后可以卸载Swagger.NET,此处不需要! 安装完毕后屏蔽以下代码 ...
- ecshop3.0.0 release0518 SQL注入
bugscan上的漏洞,自己复现了一下 注入在根目录下的flow.php elseif ($_REQUEST['step'] == 'repurchase') { include_once('incl ...
- httpClient使用中报错org.apache.commons.httpclient.HttpMethodBase - Going to buffer response body of large or unknown size.
在使用HttpClient发送请求,使用httpMethod.getResponseBodyAsString();时当返回值过大时会报错: org.apache.commons.httpclient. ...
- I/O的控制方式——查询,中断,dma(转)
早期,I/O串行,查询方式.发展,I/O并行,两种方式其一是中断方式,其二是dma方式,使得外部设备能直接与主存储器信息交换,减轻了cpu的工作量.技术继续发展,出现通道结构,实质上为高性能的dma控 ...
- MySQL集群系列1:2台机器搭建双主集群
先配置静态IP 2台机器mysql密码一样,最好在同一局域网内,最好在mysql刚安装时就配置好,后面有数据了不好同步. 本文实现了2台机器mysql数据同步成功: 配置my.cnf 先关闭防火墙 s ...
- pl/sql 实例精解 07
这章主要讨论 oracle11g 新特性, continue, continue when 语句 continue 的作用同其他编程语言一样. continue when condition 只是当条 ...
- 打开.py文件的方法
用IDLE打开这个文件,然后按F5,系统就自动开始运行这个python程序,然后当前运行目录就跳转到这个目录了
- Could not load type ‘System.ServiceModel.Activation.HttpModule’ from&
1. 部署网站到IIS7.5,Window 2008的时候出现这个错误 2. 错误信息 Server Error in ‘/’ Application. Could not load type ‘ ...
- linux中常用压缩与解压命令
一. tar文件的解压 tar -xvf db.tar 二. zip文件的压缩与解压 压缩 zip -r dest_name.zip directory_to_compress 解压 unzip de ...