昨日内容回顾
1.Flask 路由
- endpoint="user" # 反向 url 地址
- url_address = url_for("user")
- methods = ["GET","POST"] # 允许请求进入视图函数的方式
- redirect_to # 在进入视图函数之前重定向
- /index/<nid> # 动态参数路由 <int:nid> def index(nid)
- strict_slashes # 是否严格要求路由地址 /
- defaults={
- "nid":1
- } # def index(nid)
2.Flask 初始化配置 (实例化):
- template_folder # 指定模板路径
- static_url_path # 指定静态文件目录的 URL 地址
- static_folder # 指定静态文件目录路径
3.Flask 对象配置
- DEBUG #开发模式的调试功能 True False
- App.config.from_object(class) # 通过对象的方式导入配置
- secret_key # 开启 session 功能的时候需要添加的配置
- Blueprint
1. 将功能和主程序分离, 注册
2.bl = Blueprint("dongdong",__name__)
3. 注册 register_blueprint(bl)
- 5.send_file jsonify
- 1.send_file # 打开并返回文件 content-type: 文件类型
- 2.jsonify # 将一个字符串 转为 JSON 格式 加入 content-type:application/JSON 头
6. 特殊的装饰器:
- 1.before_request # 在请求进入视图函数之前执行的函数 (登录认证)
- 2.after_request # 在请求响应回浏览器之前执行的函数
- 3.before_first_request # 在第一次请求进入视图函数之前执行的函数
- 4.errorheader(404) # 当遇到此类错误响应的时候 (自定义错误页面)
- 7.flash
- 1.flash("msg","tag") # 闪现存储
- 2.get_flashed_messages(category_filter=["tag"]) # 闪现取值
只要用到了 get_flashed_messages 就一定清空 flash
View Code
转:
websocket
WebSocket 是什么?
WebSocket http://websocket.org/ 是一种网络通信协议. RFC6455 https://tools.ietf.org/html/rfc6455 定义了它的通信标准.
WebSocket 是 HTML5 开始提供的一种在单个 TCP 连接上进行全双工通讯的协议.
为什么需要 WebSocket ?
了解计算机网络协议的人, 应该都知道: HTTP 协议是一种无状态的, 无连接的, 单向的应用层协议. 它采用了请求 / 响应模型. 通信请求只能由客户端发起, 服务端对请求做出应答处理.
这种通信模型有一个弊端: HTTP 协议无法实现服务器主动向客户端发起消息.
这种单向请求的特点, 注定了如果服务器有连续的状态变化, 客户端要获知就非常麻烦. 大多数 Web 应用程序将通过频繁的异步 JavaScript 和 xml(Ajax) 请求实现长轮询. 轮询的效率低, 非常浪费资源 (因为必须不停连接, 或者 HTTP 连接始终打开).
因此, 工程师们一直在思考, 有没有更好的方法. WebSocket 就是这样发明的. WebSocket 连接允许客户端和服务器之间进行全双工通信, 以便任一方都可以通过建立的连接将数据推送到另一端. WebSocket 只需要建立一次连接, 就可以一直保持连接状态. 这相比于轮询方式的不停建立连接显然效率要大大提高.
WebSocket 如何工作?
Web 浏览器和服务器都必须实现 WebSockets 协议来建立和维护连接. 由于 WebSockets 连接长期存在, 与典型的 HTTP 连接不同, 对服务器有重要的影响.
基于多线程或多进程的服务器无法适用于 WebSockets, 因为它旨在打开连接, 尽可能快地处理请求, 然后关闭连接. 任何实际的 WebSockets 服务器端实现都需要一个异步服务器.
WebSocket 客户端
在客户端, 没有必要为 WebSockets 使用 JavaScript 库. 实现 WebSockets 的 Web 浏览器将通过 WebSockets 对象公开所有必需的客户端功能 (主要指支持 Html5 的浏览器).
客户端 API
以下 API 用于创建 WebSocket 对象.
var Socket = new WebSocket(url, [protocol] );
以上代码中的第一个参数 url, 指定连接的 URL. 第二个参数 protocol 是可选的, 指定了可接受的子协议.
WebSocket 属性
以下是 WebSocket 对象的属性. 假定我们使用了以上代码创建了 Socket 对象:
属性 | 描述 |
---|---|
Socket.readyState | 只读属性 & nbsp;readyState 表示连接状态,可以是以下值:0 - 表示连接尚未建立。1 - 表示连接已建立,可以进行通信。2 - 表示连接正在进行关闭。3 - 表示连接已经关闭或者连接不能打开。 |
Socket.bufferedAmount | 只读属性 & nbsp;bufferedAmount 已被 send() 放入正在队列中等待传输,但是还没有发出的 UTF-8 文本字节数。 |
WebSocket 事件
以下是 WebSocket 对象的相关事件. 假定我们使用了以上代码创建了 Socket 对象:
事件 | 事件处理程序 | 描述 |
---|---|---|
open | Socket.onopen | 连接建立时触发 |
message | Socket.onmessage | 客户端接收服务端数据时触发 |
error | Socket.onerror | 通信发生错误时触发 |
close | Socket.onclose | 连接关闭时触发 |
WebSocket 方法
以下是 WebSocket 对象的相关方法. 假定我们使用了以上代码创建了 Socket 对象:
方法 | 描述 |
---|---|
Socket.send() | 使用连接发送数据 |
Socket.close() | 关闭连接 |
示例
- // 初始化一个 WebSocket 对象
- var ws = new WebSocket("ws://localhost:9998/echo");
- // 建立 Web socket 连接成功触发事件
- ws.onopen = function () {
- // 使用 send() 方法发送数据
- ws.send("发送数据");
- alert("数据发送中...");
- };
- // 接收服务端数据时触发事件
- ws.onmessage = function (evt) {
- var received_msg = evt.data;
- alert("数据已接收...");
- };
- // 断开 Web socket 连接成功触发事件
- ws.onclose = function () {
- alert("连接已关闭...");
- };
WebSocket 服务端
WebSocket 在服务端的实现非常丰富. Node.JS,Java,C++,Python 等多种语言都有自己的解决方案.
以下, 介绍我在学习 WebSocket 过程中接触过的 WebSocket 服务端解决方案.
群聊
项目结构如下:
./
├── chat.py
└── templates
└── many_people.HTML
服务器
这里使用 flask 作为服务器, python 版本为 3.6.5
安装模块
pip install gevent-websocket
chat.py
- from flask import Flask,request,render_template
- from geventwebsocket.handler import WebSocketHandler
- from gevent.pywsgi import WSGIServer
- from geventwebsocket.websocket import WebSocket
- import JSON
- App = Flask(__name__)
- user_dict = {} # 空字典, 用来存放用户名和发送消息
- @App.route("/<username>") # 参数为用户名
- def index(username):
- # 获取请求的 WebSocket 对象
- user_socket = request.environ.get("wsgi.websocket") # type:WebSocket
- if user_socket:
- # 设置键值对
- # {'xiao': <geventwebsocket.websocket.WebSocket object at 0x0000020F6F6B8DB0>}
- user_dict[username] = user_socket
- print(user_dict)
- # 循环, 接收消息
- while True:
- # 接收消息
- msg = user_socket.receive()
- print(msg)
- # 反序列化数据, 因为前端发送的是 JSON
- recv_msg = JSON.loads(msg)
- print(recv_msg)
- # 构造数据结构
- send_msg = {
- # 获取用户名
- "username":recv_msg.get("username"),
- # 获取消息
- "msg":recv_msg.get("msg")
- }
- # 遍历字典
- for i in user_dict.values():
- # 这里的 i 就是 websocket 对象
- # 判断 websocket 对象等于请求的 websocket 对象
- if i == user_socket:
- # 跳过循环
- continue
- # 发送数据, 对数据做序列化
- i.send(JSON.dumps(send_msg))
- @App.route("/ws")
- def ws():
- return render_template("many_people.html")
- if __name__ == '__main__':
- # 创建一个 WebSocket 服务器
- http_serv = WSGIServer(("0.0.0.0",5000),App,handler_class=WebSocketHandler)
- # 开始监听 HTTP 请求
- http_serv.serve_forever()
- # App.run("0.0.0.0", 5000, debug=True)
客户端
- <!DOCTYPE HTML>
- <HTML lang="en">
- <head>
- <meta charset="UTF-8">
- <title>
- Title
- </title>
- </head>
- <body>
- 你的昵称:
- <input type="text" id="nickname">
- <button onclick="connws()">
- 连接服务器
- </button>
- <br>
- <br>
- 发送消息:
- <input type="text" id="talk">
- <button onclick="send_msg()">
- 发送信息
- </button>
- <br>
- <br>
- <div style="width: 500px;height: 100%;border: 1px red solid;" id="text">
- </div>
- </body>
- <script type="application/javascript">
- var user_name = null; // 用户名
- var ws = null; //WebSocket 对象, 默认设置为空
- // 连接 ws
- function connws() {
- // 获取输入框中的用户名
- user_name = document.getElementById("nickname").value;
- // 创建 WebSocket 对象
- ws = new WebSocket("ws://127.0.0.1:5000/" + user_name);
- // 客户端接收服务端数据时触发
- ws.onmessage = function(data) {
- // 反序列化接收数据
- var recv_msg = JSON.parse(data.data);
- console.log(recv_msg);
- // 执行自定义函数 createDiv, 传入 2 个参数
- createDiv(recv_msg.username, recv_msg.msg);
- };
- }
- // 发送消息
- function send_msg() {
- // 获取输入框的发送消息
- var talk = document.getElementById("talk").value;
- // 执行自定义函数 createDiv
- createDiv("w", talk);
- // 组件发送数据对象
- send_str = {
- username: user_name,
- // 用户名
- msg: talk // 消息
- };
- // 使用连接发送数据, 序列化对象
- ws.send(JSON.stringify(send_str));
- };
- // 显示聊天信息
- function createDiv(self, content) {
- // 创建 div 标签
- var divtag = document.createElement("div");
- // 定义格式
- var who = self + ":";
- // 判断参数为 w 时
- if (self == "w") {
- // 替换字符串
- who = "我 :"
- }
- // 修改显示框的 text 属性
- divtag.innerText = who + content;
- // 获取显示框
- var text = document.getElementById("text");
- // appendChild() 方法向节点添加最后一个子节点
- // 添加一个 div 标签
- text.appendChild(divtag);
- }
- </script>
- </HTML>
View Code
启动 flask 程序, 访问页面: http://127.0.0.1:5000/ws
开 3 个网页, 输入昵称, 开始聊天. 注意: 每个网页, 连接服务器一次, 就可以了!
还可以多开几个网页, 几个人, 可以同时聊天.
单聊
单聊, 需要指定一个用户, 才能发起一对一聊天!
项目结构如下:
./
├── one_chat.py
└── templates
└── single_chat.HTML
服务器
one_chat.py
- from flask import Flask,request,render_template
- from geventwebsocket.handler import WebSocketHandler
- from gevent.pywsgi import WSGIServer
- from geventwebsocket.websocket import WebSocket
- import JSON
- App = Flask(__name__)
- user_dict = {} # 空字典, 用来存放用户名和发送消息
- @App.route("/<username>") # 参数为用户名
- def index(username):
- # 获取请求的 WebSocket 对象
- user_socket = request.environ.get("wsgi.websocket") # type:WebSocket
- if user_socket:
- # 设置键值对
- # {'xiao': <geventwebsocket.websocket.WebSocket object at 0x0000020F6F6B8DB0>}
- user_dict[username] = user_socket
- print(user_dict)
- # 循环, 接收消息
- while True:
- # 接收消息
- msg = user_socket.receive()
- # print(msg)
- # 反序列化数据, 因为前端发送的是 JSON
- recv_msg = JSON.loads(msg)
- print(recv_msg)
- # 构造数据结构
- send_msg = {
- # 消息
- "msg": recv_msg.get("msg"),
- # 来自于哪个用户
- "from_user": username,
- }
- # 获取聊天对象的名字
- to_user = user_dict.get(recv_msg.get("to_user"))
- # 发送数据
- to_user.send(JSON.dumps(send_msg))
- @App.route("/ws")
- def ws():
- return render_template("single_chat.html")
- if __name__ == '__main__':
- # 创建一个 WebSocket 服务器
- http_serv = WSGIServer(("0.0.0.0",5000),App,handler_class=WebSocketHandler)
- # 开始监听 HTTP 请求
- http_serv.serve_forever()
- # App.run("0.0.0.0", 5000, debug=True)
- View Code
客户端
single_chat.HTML
- <!DOCTYPE HTML>
- <HTML lang="en">
- <head>
- <meta charset="UTF-8">
- <title>
- Title
- </title>
- </head>
- <body>
- 你的昵称:
- <input type="text" id="nickname">
- <button onclick="connws()">
- 连接服务器
- </button>
- <br>
- 与谁说话:
- <input type="text" id="sender">
- <br>
- 发送消息:
- <input type="text" id="talk">
- <button onclick="send_msg()">
- 发送信息
- </button>
- <br/>
- <br/>
- <div style="width: 500px;height: 100%;border: 1px red solid;" id="text">
- </div>
- </body>
- <script type="application/javascript">
- var user_name = null; // 用户名
- var ws = null; //WebSocket 对象, 默认设置为空
- // 连接 ws
- function connws() {
- // 获取输入框中的用户名
- user_name = document.getElementById("nickname").value;
- // 创建 WebSocket 对象
- ws = new WebSocket("ws://127.0.0.1:5000/" + user_name);
- // 客户端接收服务端数据时触发
- ws.onmessage = function(data) {
- // 反序列化接收数据
- var recv_msg = JSON.parse(data.data);
- console.log(recv_msg);
- // 执行自定义函数 createDiv, 传入 2 个参数
- createDiv(recv_msg.from_user, recv_msg.msg);
- };
- }
- function send_msg() {
- // 获取输入框的发送消息
- var talk = document.getElementById("talk").value;
- // 获取输入框的聊天对象
- var sender = document.getElementById("sender").value;
- // 执行自定义函数 createDiv
- createDiv("w", talk);
- // 构造发送数据对象
- send_str = {
- msg: talk,
- // 消息
- to_user: sender,
- // 对方
- };
- // 使用连接发送数据, 序列化对象
- ws.send(JSON.stringify(send_str));
- };
- // 显示聊天信息
- function createDiv(self, content) {
- // 创建 div 标签
- var divtag = document.createElement("div");
- // 定义格式
- var who = self + ":";
- // 判断参数为 w 时
- if (self == "w") {
- // 替换字符串
- who = "我 :"
- }
- // 修改显示框的 text 属性
- divtag.innerText = who + content;
- // 获取显示框
- var text = document.getElementById("text");
- // appendChild() 方法向节点添加最后一个子节点
- // 添加一个 div 标签
- text.appendChild(divtag);
- }
- </script>
- </HTML>
View Code
效果如下:
总结:
1.DButils 数据库连接池
创建连接池同时创建连接
用到连接时从连接池中抽取一个连接
释放连接时将连接放回连接池中
节省与 MySQL 的通讯次数和时长
2.Websocket 通讯协议
Web + socket
QQ 即时通讯软件 97
初期轮询:
QQ 联众 软件不断的循环访问服务器问它有没有给我发送的消息
优点: 响应及时
缺点: 浪费 CPU 资源, 浪费带宽
长轮询:
当客户端发起询问, 服务器说你等着 1 分钟之后, 你再来问我
断开再次发起连接, 服务器帮你轮询
优点: 响应及时
缺点: 用户一旦形成规模, 服务器消耗是致命的
新的协议 websocket
规定了一个数据格式
收发数据
该收就收
该发就发
3. 群聊
4. 私聊
View Code
来源: http://www.bubuko.com/infodetail-2975075.html