引入

 Web端即时通讯技术:即时通讯技术简单的说就是实现这样一种功能:服务器端可以即时地将数据的更新或变化反应到客户端,例如消息即时推送等功能都是通过这种技术实现的。但是在Web中,由于浏览器的限制,实现即时通讯需要借助一些方法。这种限制出现的主要原因是,一般的Web通信都是浏览器先发送请求到服务器,服务器再进行响应完成数据的现实更新。

  实现Web端即时通讯的方法:实现即时通讯主要有四种方式,它们分别是轮询、长轮询(comet)、长连接(SSE)、WebSocket。它们大体可以分为两类,一种是在HTTP基础上实现的,包括短轮询、comet和SSE;另一种不是在HTTP基础上实现是,即WebSocket。下面分别介绍一下这四种轮询方式,以及它们各自的优缺点。

当我们要实现一个实时投票系统,或者是实时通讯系统,我们的页面数据总需要更新

我们不能让用户一直去刷新页面。所以就有了轮询,长轮询,以及websock的出现

轮询

既然我想要实时获取后端的数据,那我就每隔2秒给后端发一次请求

这种我们就叫轮询~那它会有一些缺点就是存在延时~就算每秒发一次~也会存在一定的延迟

下面我们看下轮询的代码:

from flask import Flask, render_template, request, jsonify

app = Flask(__name__)

USERS = {
1: {"name": "悟空", "count": 0},
2: {"name": "悟能", "count": 0},
3: {"name": "悟净", "count": 0}, } @app.route("/")
def index():
return render_template("index.html", users=USERS) @app.route("/vote", methods=["POST"])
def vote():
uid = request.json.get("uid")
USERS[uid]["count"] += 1
return "投票成功" @app.route("/get_vote")
def get_vote():
return jsonify(USERS) if __name__ == '__main__':
app.run()

app.py

<!DOCTYPE html>
<html lang="en"> <head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Title</title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script src="https://cdn.bootcss.com/axios/0.19.0-beta.1/axios.js"></script> </head>
<body>
<h1>选丑大赛</h1> <ul>
{% for key, value in users.items()%}
<li id="{{key}}" onclick="vote({{key}})">{{value.name}} ({{value.count}})</li>
{% endfor %}
</ul> <script>
function vote(uid) {
axios.request({
url: "/vote",
method: "POST",
data: {
"uid": uid
}
}).then(function (res) {
console.log(res.data)
})
} function get_vote() {
axios.request({
url: "/get_vote",
method: "GET"
}).then(function (res) {
console.log(res)
for(let key in res.data){
let liEle = document.getElementById(key);
let username = res.data[key]["name"]
let count = res.data[key]["count"]
liEle.innerText = `${username} (${count})`
}
})
} window.onload = function () {
setInterval(get_vote, 2000)
} </script> </body>
</html>

index.html

长轮询

轮询缺点就是延迟,那么如果前端发送过来请求,如果没有数据的更新

后端的请求就阻塞了,直到有数据返回或者超时再返回,这样延迟就可以得到很好的解决

python中有个queue对象,当我们从这个队列里拿不到值的时候,可以阻塞住请求的

import queue
from flask import Flask app = Flask(__name__)
q = queue.Queue() @app.route("/get")
def index():
try:
val = q.get(timeout=20)
except queue.Empty:
val = "超时"
return val @app.route("/vote")
def vote():
q.put("")
return "投票成功" if __name__ == '__main__':
app.run()

queueDemo.py

如果我为每个请求都建立一个q对象,然后阻塞住他们的请求,有数据更新的时候,给他们的q对象返回值就可以了。

from flask import Flask, render_template, request, jsonify, session
import queue
import uuid app = Flask(__name__)
app.secret_key = "lajdgia" USERS = {
1: {"name": "悟空", "count": 0},
2: {"name": "悟能", "count": 0},
3: {"name": "悟净", "count": 0}, }
# 为每个用户建立一个q对象
# 以用户的uuid为key 值为q对象
Q_DICT = {} @app.route("/")
def index():
user_uuid = str(uuid.uuid4())
session["user_uuid"] = user_uuid
Q_DICT[user_uuid] = queue.Queue()
return render_template("index2.html", users=USERS) @app.route("/vote", methods=["POST"])
def vote():
# 投票 循环q对象的dict 给每个q对象返回值
uid = request.json.get("uid")
USERS[uid]["count"] += 1
for q in Q_DICT.values():
q.put(USERS)
return "投票成功" @app.route("/get_vote", methods=["POST", "GET"])
def get_vote():
# 获取投票结果 去自己的q对象里取值 没有夯住 知道有或者超时返回
user_uuid = session.get("user_uuid")
q = Q_DICT[user_uuid]
try:
users = q.get(timeout=30)
except queue.Empty:
users = ""
return jsonify(users) if __name__ == '__main__':
app.run()

app2.py

<!DOCTYPE html>
<html lang="en"> <head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Title</title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script src="https://cdn.bootcss.com/axios/0.19.0-beta.1/axios.js"></script> </head>
<body>
<h1>选丑大赛</h1> <ul>
{% for key, value in users.items()%}
<li id="{{key}}" onclick="vote({{key}})">{{value.name}} ({{value.count}})</li>
{% endfor %}
</ul> <script>
function vote(uid) {
axios.request({
url: "/vote",
method: "POST",
data: {
"uid": uid
}
}).then(function (res) {
console.log(res.data)
})
} function get_votes() {
axios.request({
url: "/get_vote",
method: "POST"
}).then(function (res) {
console.log(res);
if(res.data != ""){
for(let key in res.data){
let liEle = document.getElementById(key);
let username = res.data[key]["name"]
let count = res.data[key]["count"]
liEle.innerText = `${username} (${count})`
}
}
get_votes()
})
} window.onload = function () {
get_votes()
} </script> </body>
</html>

index2.html

websocket

websocket是一个协议,协议规定

连接的时候需要握手,发送的数据需要加密~~连接之后不断开

Flask不带websocket,我们需要下载

下载:pip install gevent-websocket

from flask import Flask, request, render_template
from geventwebsocket.handler import WebSocketHandler
from gevent.pywsgi import WSGIServer
import json app = Flask(__name__) USERS = {
1: {"name": "悟空", "count": 0},
2: {"name": "悟能", "count": 0},
3: {"name": "悟净", "count": 0}, } @app.route("/")
def index():
return render_template("index3.html", users=USERS) WEBSOCKET_LIST = []
@app.route("/vote")
def vote():
ws = request.environ.get("wsgi.websocket")
if not ws:
return "HTTP请求"
WEBSOCKET_LIST.append(ws)
while True:
uid = ws.receive()
if not uid:
WEBSOCKET_LIST.remove(ws)
ws.close()
break
uid = int(uid)
USERS[uid]["count"] += 1
name = USERS[uid]["name"]
new_count = USERS[uid]["count"]
for client in WEBSOCKET_LIST:
client.send(json.dumps({"uid": uid, "name": name, "count": new_count})) if __name__ == '__main__':
http_server = WSGIServer(('127.0.0.1', 5000), app, handler_class=WebSocketHandler)
http_server.serve_forever()

app3.py

<!DOCTYPE html>
<html lang="en"> <head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Title</title>
<script src="https://cdn.bootcss.com/axios/0.19.0-beta.1/axios.js"></script> </head>
<body>
<h1>选丑大赛</h1> <ul>
{% for (key, value) in users.items() %}
<li onclick="vote({{key}})" id="{{key}}">{{value.name}} ({{value.count}})</li>
{% endfor%} </ul> <script>
let ws = new WebSocket('ws://127.0.0.1:5000/vote') function vote(uid) {
ws.send(uid)
}
ws.onmessage = function (event) {
let data = JSON.parse(event.data);
let liEle = document.getElementById(data.uid);
liEle.innerText = `${data.name} (${data.count})`
} </script> </body>
</html>

index3.html

轮询、长轮询、websock的更多相关文章

  1. 使用轮询&长轮询实现网页聊天室

    前言 如果有一个需求,让你构建一个网络的聊天室,你会怎么解决? 首先,对于HTTP请求来说,Server端总是处于被动的一方,即只能由Browser发送请求,Server才能够被动回应. 也就是说,如 ...

  2. Apollo 3 定时/长轮询拉取配置的设计

    前言 如上图所示,Apollo portal 更新配置后,进行轮询的客户端获取更新通知,然后再调用接口获取最新配置.不仅仅只有轮询,还有定时更新(默认 5 分钟一次).目的就是让客户端能够稳定的获取到 ...

  3. 了解轮询、长轮询、长连接、websocket

    业务开发中我们往往会有一些需要即时通信的场景,比如微信扫码登录.聊天功能. 下面这四种方式都可以实现即时通信. 轮询: 浏览器通过定时器每隔一段时间向服务器端发送请求,服务器端收到请求并响应请求.没有 ...

  4. Tornado长轮询和WebSocket

    Http协议是一种请求响应式协议, 不允许服务端主动向客户端发送信息. 短轮询是一种简单的实现服务端推送消息的解决方案, 客户端以一定间隔自动向服务端发送刷新请求, 服务端返回要推送的消息作为响应. ...

  5. 轮询、长轮询、长连接、websocket

    Web端即时通讯技术:即时通讯技术简单的说就是实现这样一种功能:服务器端可以即时地将数据的更新或变化反应到客户端,例如消息即时推送等功能都是通过这种技术实现的.但是在Web中,由于浏览器的限制,实现即 ...

  6. es6- Generator函数实现长轮询

    1.Generator 函数是 ES6 提供的一种异步编程解决方案,语法行为与传统函数完全不同. 语法上,首先可以把它理解成,Generator 函数是一个状态机,封装了多个内部状态.形式上,Gene ...

  7. 长连接、短连接、长轮询和WebSocket

    //转发,格式待整理 2017-08-0519784View0 对这四个概念不太清楚,今天专门搜索了解一下,总结一下: 长连接:在HTTP 1.1,客户端发出请求,服务端接收请求,双方建立连接,在服务 ...

  8. http轮询,长轮询

    轮询,长轮询 轮询 轮询:客户端定时向服务器发送Ajax请求,服务器接到请求后马上返回响应信息并关闭连接. 优点:后端程序编写比较容易. 缺点:请求中有大半是无用,浪费带宽和服务器资源. 实例:适于小 ...

  9. http长轮询&短轮询

    http 协议介绍: http 协议是请求/响应范式的, 每一个 http 响应都是由一个对应的 http 请求产生的; http 协议是无状态的, 多个 http 请求之间是没有关系的. http ...

随机推荐

  1. PV、UV、IP、TPS、QPS、RPS、两天、吞吐量、 并发用户数 术语

    跟网站打交道,经常可以听到数据分析之类的专有名词,如pv多少.ip多少.tps多少之类的问题.下面就这些常见的数据给出其释义. PV   即 page view,页面浏览量         用户每一次 ...

  2. H5 28-优先级之权重问题

    28-优先级之权重问题 我是段落 <!DOCTYPE html> <html lang="en"> <head> <meta charse ...

  3. JS 有趣的JS

    一. var arr = []; for (var i = 0; i < 3; i++) { arr[i] = function() { console.log(i+'__') // 3 3 3 ...

  4. Win10系统如何安装Linux Mint

    导读 随着windows10系统免费升级期限的靠近,越来越多朋友都将自己的电脑系统升级到了win10正式版.今天,小编就要在这里为大家分享Windows10系统安装Linux Mint的方法,希望能够 ...

  5. 牛客练习赛B题 筱玛的排列(找递推规律)

    链接:https://ac.nowcoder.com/acm/contest/342/B来源:牛客网 筱玛的排列 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 524288K,其他语 ...

  6. git的用法步骤讲解

    1.创建全局的本地用户名 git config --global user.name "teamemory" git config --global user.email &quo ...

  7. js中的join(),reverse()与 split()函数用法解析

    <script> /* * 1:arrayObject.reverse() * 注意: 该方法会改变原来的数组,而不会创建新的数组.此函数可以将数组倒序排列 * 2:arrayObject ...

  8. Java面试题详解四:==和equals的去别

    一,功能 1.对于== 作用于基本数据类型的变量,比较的存储的值是否相等, 作用于引用类型的变量,比较的是其所指向的对象的地址是否相同(即是否是同一个对象) 2.对于equals Object的equ ...

  9. React Native之微信分享(iOS Android)

    React Native之微信分享(iOS Android) 在使用React Native开发项目的时候,基本都会使用到微信好友或者微信朋友圈分享功能吧,那么今天我就带大家实现以下RN微信好友以及朋 ...

  10. C#设计模式之1:策略模式

    首先需要说明的是该系列的所有内容都是基于headfirst设计模式来描述的.因为我之前也看过不少关于设计模式的书,还是发现这本最好,因为这本书里面给出的例子是最贴切实际的.不说了,开始这个系列吧! 策 ...